text: /****************************************************************************
  **
  ** Copyright (C) 2016 The Qt Company Ltd.
  ** Contact: https://www.qt.io/licensing/
  **
  ** This file is part of the test suite of the Qt Toolkit.
  **
  ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
  ** Commercial License Usage
  ** Licensees holding valid commercial Qt licenses may use this file in
  ** accordance with the commercial license agreement provided with the
  ** Software or, alternatively, in accordance with the terms contained in
  ** a written agreement between you and The Qt Company. For licensing terms
  ** and conditions see https://www.qt.io/terms-conditions. For further
  ** information use the contact form at https://www.qt.io/contact-us.
  **
  ** GNU General Public License Usage
  ** Alternatively, this file may be used under the terms of the GNU
  ** General Public License version 3 as published by the Free Software
  ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
  ** included in the packaging of this file. Please review the following
  ** information to ensure the GNU General Public License requirements will
  ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
  **
  ** $QT_END_LICENSE$
  **
  ****************************************************************************/
  
  
  #include <QtTest/QtTest>
  
  #include <qtextdocument.h>
  #include <qtexttable.h>
  #include <qvariant.h>
  #include <qtextdocumentfragment.h>
  #include <qabstracttextdocumentlayout.h>
  #include <qtextlayout.h>
  #include <qtextcursor.h>
  #include <qtextobject.h>
  #include <qdebug.h>
  
  #include <private/qtextcursor_p.h>
  
  QT_FORWARD_DECLARE_CLASS(QTextDocument)
  
  class tst_QTextCursor : public QObject
  {
      Q_OBJECT
  
  private slots:
      void init();
      void cleanup();
      void navigation1();
      void navigation2_data();
      void navigation2();
      void navigation3();
      void navigation4();
      void navigation5();
      void navigation6();
      void navigation7();
      void navigation8();
      void navigation9();
      void navigation10();
      void movePositionEndOfLine();
      void insertBlock();
      void insertWithBlockSeparator1();
      void insertWithBlockSeparator2();
      void insertWithBlockSeparator3();
      void insertWithBlockSeparator4();
      void clearObjectType1();
      void clearObjectType2();
      void clearObjectType3();
      void comparisonOperators1();
      void comparisonOperators2();
      void selection1();
      void dontCopyTableAttributes();
  
      void checkFrame1();
      void checkFrame2();
  
      void tableMovement();
      void selectionsInTable();
  
      void insertBlockToUseCharFormat();
  
      void selectedText();
  
      void insertBlockShouldRemoveSelection();
      void insertBlockShouldRemoveSelection2();
      void mergeCellShouldUpdateSelection();
  
      void joinPreviousEditBlock();
  
      void setBlockFormatInTable();
  
      void blockCharFormat();
      void blockCharFormat2();
      void blockCharFormat3();
      void blockCharFormatOnSelection();
  
      void anchorInitialized1();
      void anchorInitialized2();
      void anchorInitialized3();
  
      void selectWord();
      void selectWordWithSeparators_data();
      void selectWordWithSeparators();
      void startOfWord();
      void selectBlock();
      void selectVisually();
  
      void insertText();
  
      void insertFragmentShouldUseCurrentCharFormat();
  
      void endOfLine();
  
      void editBlocksDuringRemove();
      void selectAllDuringRemove();
  
      void update_data();
      void update();
  
      void disallowSettingObjectIndicesOnCharFormats();
  
      void blockAndColumnNumber();
  
      void clearCells();
  
      void task244408_wordUnderCursor_data();
      void task244408_wordUnderCursor();
  
      void adjustCursorsOnInsert();
  
      void cursorPositionWithBlockUndoAndRedo();
      void cursorPositionWithBlockUndoAndRedo2();
      void cursorPositionWithBlockUndoAndRedo3();
  
      void joinNonEmptyRemovedBlockUserState();
  
  private:
      int blockCount();
  
      QTextDocument *doc;
      QTextCursor cursor;
  };
  
  void tst_QTextCursor::init()
  {
      doc = new QTextDocument;
      cursor = QTextCursor(doc);
  }
  
  void tst_QTextCursor::cleanup()
  {
      cursor = QTextCursor();
      delete doc;
      doc = 0;
  }
  
  void tst_QTextCursor::navigation1()
  {
  
      cursor.insertText("Hello World");
      QCOMPARE(doc->toPlainText(), QLatin1String("Hello World"));
  
      cursor.movePosition(QTextCursor::End);
      QCOMPARE(cursor.position(), 11);
      cursor.deletePreviousChar();
      QCOMPARE(cursor.position(), 10);
      cursor.deletePreviousChar();
      cursor.deletePreviousChar();
      cursor.deletePreviousChar();
      cursor.deletePreviousChar();
      cursor.deletePreviousChar();
      QCOMPARE(doc->toPlainText(), QLatin1String("Hello"));
  
      QTextCursor otherCursor(doc);
      otherCursor.movePosition(QTextCursor::Start);
      otherCursor.movePosition(QTextCursor::Right);
      cursor = otherCursor;
      cursor.movePosition(QTextCursor::Right);
      QVERIFY(cursor != otherCursor);
      otherCursor.insertText("Hey");
      QCOMPARE(cursor.position(), 5);
  
      doc->undo();
      QCOMPARE(cursor.position(), 2);
      doc->redo();
      QCOMPARE(cursor.position(), 5);
  
      doc->undo();
  
      doc->undo();
      QCOMPARE(doc->toPlainText(), QLatin1String("Hello World"));
  
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 6);
      QCOMPARE(cursor.position(), 6);
      otherCursor = cursor;
      otherCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 2);
      otherCursor.deletePreviousChar();
      otherCursor.deletePreviousChar();
      otherCursor.deletePreviousChar();
      QCOMPARE(cursor.position(), 5);
  
      cursor.movePosition(QTextCursor::End);
      cursor.insertBlock();
      {
          int oldPos = cursor.position();
          cursor.movePosition(QTextCursor::End);
          QCOMPARE(cursor.position(), oldPos);
      }
      QVERIFY(cursor.atBlockStart());
      QCOMPARE(cursor.position(), 9);
  
      QTextCharFormat fmt;
      fmt.setForeground(Qt::blue);
      cursor.insertText("Test", fmt);
      QCOMPARE(fmt, cursor.charFormat());
      QCOMPARE(cursor.position(), 13);
  }
  
  void tst_QTextCursor::navigation2_data()
  {
      QTest::addColumn<QStringList>("sl");
      QTest::addColumn<QList<QVariant> >("movement");
      QTest::addColumn<int>("finalPos");
  
      QTest::newRow("startBlock1") << QStringList("Happy happy happy joy joy joy")
                                << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)) << 0;
      QTest::newRow("endBlock1") << QStringList("Happy happy happy joy joy joy")
                              << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)
                                       << QVariant(QTextCursor::EndOfBlock)) << 29;
      QTest::newRow("startBlock2") << QStringList("Happy happy happy joy joy joy")
                                << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)
                                       << QVariant(QTextCursor::EndOfBlock)
                                       << QVariant(QTextCursor::StartOfBlock)) << 0;
      QTest::newRow("endBlock2") << QStringList("Happy happy happy joy joy joy")
                              << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)
                                       << QVariant(QTextCursor::EndOfBlock)
                                       << QVariant(QTextCursor::StartOfBlock)
                                       << QVariant(QTextCursor::EndOfBlock)
                                       ) << 29;
      QTest::newRow("multiBlock1") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock))
                               << 18;
      QTest::newRow("multiBlock2") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)
                                                     << QVariant(QTextCursor::EndOfBlock))
                               << 29;
      QTest::newRow("multiBlock3") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)
                                                     << QVariant(QTextCursor::StartOfBlock))
                               << 18;
      QTest::newRow("multiBlock4") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::Start)
                                                     << QVariant(QTextCursor::EndOfBlock))
                               << 17;
      QTest::newRow("multiBlock5") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::Start)
                                                     << QVariant(QTextCursor::EndOfBlock)
                                                     << QVariant(QTextCursor::EndOfBlock))
                               << 17;
      QTest::newRow("multiBlock6") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::End)
                                                     << QVariant(QTextCursor::StartOfBlock))
                               << 18;
      QTest::newRow("multiBlock7") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock))
                               << 0;
      QTest::newRow("multiBlock8") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock)
                                                     << QVariant(QTextCursor::EndOfBlock))
                               << 17;
      QTest::newRow("multiBlock9") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock)
                                                     << QVariant(QTextCursor::NextBlock))
                               << 18;
      QTest::newRow("multiBlock10") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                                 << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock)
                                                       << QVariant(QTextCursor::NextBlock)
                                                       << QVariant(QTextCursor::NextBlock))
                                 << 18;
      QTest::newRow("multiBlock11") << (QStringList() << QString("Happy happy happy")
                                                  << QString("Joy Joy Joy"))
                                 << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock)
                                                       << QVariant(QTextCursor::NextBlock)
                                                       << QVariant(QTextCursor::EndOfBlock))
                                 << 29;
      QTest::newRow("PreviousWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy"))
                                  << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord))
                                  << 26;
      QTest::newRow("PreviousWord2") << (QStringList() << QString("Happy happy happy Joy Joy Joy"))
                                  << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord)
                                                        << QVariant(QTextCursor::PreviousWord))
                                  << 22;
      QTest::newRow("EndWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy"))
                                  << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord)
                                                        << QVariant(QTextCursor::PreviousWord)
                                                        << QVariant(QTextCursor::EndOfWord))
                                  << 25;
      QTest::newRow("NextWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy"))
                                  << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord)
                                                        << QVariant(QTextCursor::PreviousWord)
                                                        << QVariant(QTextCursor::NextWord))
                                  << 26;
      QTest::newRow("NextWord2") << (QStringList() << QString("Happy happy happy Joy Joy Joy"))
                                  << (QList<QVariant>() << QVariant(QTextCursor::Start)
                                                        << QVariant(QTextCursor::NextWord)
                                                        << QVariant(QTextCursor::EndOfWord))
                                  << 11;
      QTest::newRow("StartWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord)
                                                     << QVariant(QTextCursor::PreviousWord)
                                                     << QVariant(QTextCursor::StartOfWord))
                               << 22;
      QTest::newRow("StartWord3") << (QStringList() << QString("Happy happy happy Joy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::Start)
                                                     << QVariant(QTextCursor::NextWord)
                                                     << QVariant(QTextCursor::EndOfWord)
                                                     << QVariant(QTextCursor::StartOfWord))
                               << 6;
  
      QTest::newRow("PreviousCharacter") << (QStringList() << QString("Happy happy Joy Joy"))
                               << (QList<QVariant>() << QVariant(QTextCursor::PreviousCharacter)
                                                     << QVariant(QTextCursor::PreviousCharacter))
                               << 17;
  }
  
  void tst_QTextCursor::navigation2()
  {
      QFETCH(QStringList, sl);
      QFETCH(QList<QVariant>, movement);
      int i;
      for (i = 0; i < sl.size(); ++i) {
          cursor.insertText(sl.at(i));
          if (i < sl.size() - 1)
              cursor.insertBlock();
      }
  
      for (i = 0; i < movement.size(); ++i)
          cursor.movePosition(QTextCursor::MoveOperation(movement.at(i).toInt()));
      QTEST(cursor.position(), "finalPos");
  }
  
  void tst_QTextCursor::navigation3()
  {
      cursor.insertText("a");
      cursor.deletePreviousChar();
      QCOMPARE(cursor.position(), 0);
      QVERIFY(doc->toPlainText().isEmpty());
  }
  
  void tst_QTextCursor::navigation4()
  {
      cursor.insertText("  Test  ");
  
      cursor.setPosition(4);
      cursor.movePosition(QTextCursor::EndOfWord);
      QCOMPARE(cursor.position(), 6);
  }
  
  void tst_QTextCursor::navigation5()
  {
      cursor.insertText("Test");
      cursor.insertBlock();
      cursor.insertText("Test");
  
      cursor.setPosition(0);
      cursor.movePosition(QTextCursor::EndOfBlock);
      QCOMPARE(cursor.position(), 4);
  }
  
  void tst_QTextCursor::navigation6()
  {
      // triger creation of document layout, so that QTextLines are there
      doc->documentLayout();
      doc->setTextWidth(1000);
  
      cursor.insertText("Test    ");
  
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::EndOfLine);
      QCOMPARE(cursor.position(), 8);
  }
  
  void tst_QTextCursor::navigation7()
  {
      QVERIFY(doc->isEmpty());
      for (int i = QTextCursor::Start; i <= QTextCursor::WordRight; ++i)
          QVERIFY(!cursor.movePosition(QTextCursor::MoveOperation(i)));
  
      doc->setPlainText("Hello World");
      cursor.movePosition(QTextCursor::Start);
      do {
      } while (cursor.movePosition(QTextCursor::NextCharacter));
      QVERIFY(true /*reached*/);
  }
  
  void tst_QTextCursor::navigation8()
  {
      cursor.insertList(QTextListFormat::ListDecimal);
      QCOMPARE(cursor.position(), 1);
      cursor.insertText("foo");
      QCOMPARE(cursor.position(), 4);
  
      cursor.insertList(QTextListFormat::ListCircle);
      QCOMPARE(cursor.position(), 5);
      cursor.insertText("something");
      QCOMPARE(cursor.position(), 14);
  
      cursor.movePosition(QTextCursor::PreviousCharacter);
      QCOMPARE(cursor.position(), 13);
  
      cursor.setPosition(2);
      cursor.movePosition(QTextCursor::NextCharacter);
      QCOMPARE(cursor.position(), 3);
  }
  
  void tst_QTextCursor::navigation9()
  {
      cursor.insertText("Hello  &-=+\t   World");
      cursor.movePosition(QTextCursor::PreviousWord);
      QCOMPARE(cursor.position(), 15);
      cursor.movePosition(QTextCursor::PreviousWord);
      QCOMPARE(cursor.position(), 7);
      cursor.movePosition(QTextCursor::PreviousWord);
      QCOMPARE(cursor.position(), 0);
      cursor.movePosition(QTextCursor::NextWord);
      QCOMPARE(cursor.position(), 7);
      cursor.movePosition(QTextCursor::NextWord);
      QCOMPARE(cursor.position(), 15);
  }
  
  void tst_QTextCursor::navigation10()
  {
      doc->setHtml("<html><p>just a simple paragraph.</p>"
          "<table>"
            "<tr><td>Cell number 1</td><td>another cell</td><td></td><td>previous</br>is</br>empty</td></tr>"
            "<tr><td>row 2</td><td colspan=\"2\">foo bar</td><td>last cell</td></tr>"
            "<tr><td colspan=\"3\">row 3</td><td>a</td></tr>"
          "</table></html");
      QCOMPARE(cursor.position(), 101); // end of document
      cursor.setPosition(0);
      QCOMPARE(cursor.position(), 0);
      bool ok = cursor.movePosition(QTextCursor::EndOfLine);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 24);
      ok = cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.position(), 25); // cell 1
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 39); // another..
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 52); // empty
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 53); // last on row 1
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 69); // row 2
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 75);
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 83);
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 93); // row 3
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 99);
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(!ok);
      QCOMPARE(cursor.position(), 99); // didn't move.
      QVERIFY(cursor.currentTable());
  
      // same thing in reverse...
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 93);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 83);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 75);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 69);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 53);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 52);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 39);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 25);
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(!ok);
      QCOMPARE(cursor.position(), 25); // can't leave the table
  
      ok = cursor.movePosition(QTextCursor::NextRow);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 69);
      ok = cursor.movePosition(QTextCursor::NextRow);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 93);
      ok = cursor.movePosition(QTextCursor::NextRow);
      QVERIFY(!ok);
      QCOMPARE(cursor.position(), 93); // didn't move
  
      ok = cursor.movePosition(QTextCursor::PreviousRow);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 83); // last col in row 2
      ok = cursor.movePosition(QTextCursor::PreviousRow);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 53); // last col in row 1
      ok = cursor.movePosition(QTextCursor::PreviousRow);
      QVERIFY(!ok);
      QCOMPARE(cursor.position(), 53);
  
      // test usecase of jumping over a cell
      doc->clear();
      doc->setHtml("<html><table>tr><td rowspan=\"2\">a</td><td>b</td></tr><tr><td>c</td></tr></table></html>");
      cursor.setPosition(1); // a
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 3); // b
      ok = cursor.movePosition(QTextCursor::NextCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 5); // c
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 3); // b
      ok = cursor.movePosition(QTextCursor::PreviousCell);
      QVERIFY(ok);
      QCOMPARE(cursor.position(), 1); // a
  }
  
  void tst_QTextCursor::insertBlock()
  {
      QTextBlockFormat fmt;
      fmt.setTopMargin(100);
      cursor.insertBlock(fmt);
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.blockFormat(), fmt);
  }
  
  void tst_QTextCursor::insertWithBlockSeparator1()
  {
      QString text = "Hello" + QString(QChar::ParagraphSeparator) + "World";
  
      cursor.insertText(text);
  
      cursor.movePosition(QTextCursor::PreviousBlock);
      QCOMPARE(cursor.position(), 0);
  
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.position(), 6);
  }
  
  void tst_QTextCursor::insertWithBlockSeparator2()
  {
      cursor.insertText(QString(QChar::ParagraphSeparator));
      QCOMPARE(cursor.position(), 1);
  }
  
  void tst_QTextCursor::insertWithBlockSeparator3()
  {
      cursor.insertText(QString(QChar::ParagraphSeparator) + "Hi" + QString(QChar::ParagraphSeparator));
      QCOMPARE(cursor.position(), 4);
  }
  
  void tst_QTextCursor::insertWithBlockSeparator4()
  {
      cursor.insertText(QString(QChar::ParagraphSeparator) + QString(QChar::ParagraphSeparator));
      QCOMPARE(cursor.position(), 2);
  }
  
  void tst_QTextCursor::clearObjectType1()
  {
      cursor.insertImage("test.png");
      QVERIFY(cursor.charFormat().isValid());
      QVERIFY(cursor.charFormat().isImageFormat());
      cursor.insertText("Hey");
      QVERIFY(cursor.charFormat().isValid());
      QVERIFY(!cursor.charFormat().isImageFormat());
  }
  
  void tst_QTextCursor::clearObjectType2()
  {
      cursor.insertImage("test.png");
      QVERIFY(cursor.charFormat().isValid());
      QVERIFY(cursor.charFormat().isImageFormat());
      cursor.insertBlock();
      QVERIFY(cursor.charFormat().isValid());
      QVERIFY(!cursor.charFormat().isImageFormat());
  }
  
  void tst_QTextCursor::clearObjectType3()
  {
      // like clearObjectType2 but tests different insertBlock overload
      cursor.insertImage("test.png");
      QVERIFY(cursor.charFormat().isValid());
      QVERIFY(cursor.charFormat().isImageFormat());
      QTextBlockFormat bfmt;
      bfmt.setAlignment(Qt::AlignRight);
      cursor.insertBlock(bfmt);
      QVERIFY(cursor.charFormat().isValid());
      QVERIFY(!cursor.charFormat().isImageFormat());
  }
  
  void tst_QTextCursor::comparisonOperators1()
  {
      cursor.insertText("Hello World");
  
      cursor.movePosition(QTextCursor::PreviousWord);
  
      QTextCursor startCursor = cursor;
      startCursor.movePosition(QTextCursor::Start);
  
      QVERIFY(startCursor < cursor);
  
      QTextCursor midCursor = startCursor;
      midCursor.movePosition(QTextCursor::NextWord);
  
      QVERIFY(midCursor <= cursor);
      QCOMPARE(midCursor, cursor);
      QVERIFY(midCursor >= cursor);
  
      QVERIFY(midCursor > startCursor);
  
      QVERIFY(midCursor != startCursor);
      QVERIFY(!(midCursor == startCursor));
  
      QTextCursor nullCursor;
  
      QVERIFY(!(startCursor < nullCursor));
      QVERIFY(!(nullCursor < nullCursor));
      QVERIFY(nullCursor < startCursor);
  
      QVERIFY(nullCursor <= startCursor);
      QVERIFY(!(startCursor <= nullCursor));
  
      QVERIFY(!(nullCursor >= startCursor));
      QVERIFY(startCursor >= nullCursor);
  
      QVERIFY(!(nullCursor > startCursor));
      QVERIFY(!(nullCursor > nullCursor));
      QVERIFY(startCursor > nullCursor);
  }
  
  void tst_QTextCursor::comparisonOperators2()
  {
      QTextDocument doc1;
      QTextDocument doc2;
  
      QTextCursor cursor1(&doc1);
      QTextCursor cursor2(&doc2);
  
      QVERIFY(cursor1 != cursor2);
      QCOMPARE(cursor1, QTextCursor(&doc1));
  }
  
  void tst_QTextCursor::selection1()
  {
      cursor.insertText("Hello World");
  
      cursor.setPosition(0);
      cursor.clearSelection();
      cursor.setPosition(4, QTextCursor::KeepAnchor);
  
      QCOMPARE(cursor.selectionStart(), 0);
      QCOMPARE(cursor.selectionEnd(), 4);
  }
  
  void tst_QTextCursor::dontCopyTableAttributes()
  {
      /* when pressing 'enter' inside a cell it shouldn't
       * enlarge the table by adding another cell but just
       * extend the cell */
      QTextTable *table = cursor.insertTable(2, 2);
      QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition());
      cursor.insertBlock();
      QCOMPARE(table->columns(), 2);
  }
  
  void tst_QTextCursor::checkFrame1()
  {
      QCOMPARE(cursor.position(), 0);
      QPointer<QTextFrame> frame = cursor.insertFrame(QTextFrameFormat());
      QVERIFY(frame != 0);
  
      QTextFrame *root = frame->parentFrame();
      QVERIFY(root != 0);
  
      QCOMPARE(frame->firstPosition(), 1);
      QCOMPARE(frame->lastPosition(), 1);
      QVERIFY(frame->parentFrame() != 0);
      QCOMPARE(root->childFrames().size(), 1);
  
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.selectionStart(), 1);
      QCOMPARE(cursor.selectionEnd(), 1);
  
      doc->undo();
  
      QVERIFY(!frame);
      QCOMPARE(root->childFrames().size(), 0);
  
      QCOMPARE(cursor.position(), 0);
      QCOMPARE(cursor.selectionStart(), 0);
      QCOMPARE(cursor.selectionEnd(), 0);
  
      doc->redo();
  
      frame = doc->frameAt(1);
  
      QVERIFY(frame);
      QCOMPARE(frame->firstPosition(), 1);
      QCOMPARE(frame->lastPosition(), 1);
      QVERIFY(frame->parentFrame() != 0);
      QCOMPARE(root->childFrames().size(), 1);
  
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.selectionStart(), 1);
      QCOMPARE(cursor.selectionEnd(), 1);
  
  //     cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
  //     QCOMPARE(cursor.position(), 2);
  //     QCOMPARE(cursor.selectionStart(), 0);
  //     QCOMPARE(cursor.selectionEnd(), 2);
  }
  
  void tst_QTextCursor::checkFrame2()
  {
      QCOMPARE(cursor.position(), 0);
      cursor.insertText("A");
      QCOMPARE(cursor.position(), 1);
      cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);
  
      QPointer<QTextFrame> frame = cursor.insertFrame(QTextFrameFormat());
      QTextFrame *root = frame->parentFrame();
  
      QCOMPARE(frame->firstPosition(), 1);
      QCOMPARE(frame->lastPosition(), 2);
      QVERIFY(frame->parentFrame() != 0);
      QCOMPARE(root->childFrames().size(), 1);
  
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.selectionStart(), 1);
      QCOMPARE(cursor.selectionEnd(), 2);
  
      doc->undo();
  
      QVERIFY(!frame);
      QCOMPARE(root->childFrames().size(), 0);
  
      QCOMPARE(cursor.position(), 0);
      QCOMPARE(cursor.selectionStart(), 0);
      QCOMPARE(cursor.selectionEnd(), 1);
  
      doc->redo();
  
      frame = doc->frameAt(1);
  
      QVERIFY(frame);
      QCOMPARE(frame->firstPosition(), 1);
      QCOMPARE(frame->lastPosition(), 2);
      QVERIFY(frame->parentFrame() != 0);
      QCOMPARE(root->childFrames().size(), 1);
  
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.selectionStart(), 1);
      QCOMPARE(cursor.selectionEnd(), 2);
  
      cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
      QCOMPARE(cursor.position(), 0);
      QCOMPARE(cursor.selectionStart(), 0);
      QCOMPARE(cursor.selectionEnd(), 3);
  }
  
  void tst_QTextCursor::insertBlockToUseCharFormat()
  {
      QTextCharFormat fmt;
      fmt.setForeground(Qt::blue);
      cursor.insertText("Hello", fmt);
      QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue));
  
      cursor.insertBlock();
      QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue));
  
      fmt.setForeground(Qt::red);
      cursor.insertText("Hello\nWorld", fmt);
      cursor.insertText("Blah");
      QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::red));
  
      // ### we might want a testcase for createTable, too, as it calls insertBlock, too,
      // and we might want to have the char format copied (the one that gets inserted
      // as table separators, that are undeletable)
  }
  
  void tst_QTextCursor::tableMovement()
  {
      QCOMPARE(cursor.position(), 0);
      cursor.insertText("AA");
      QCOMPARE(cursor.position(), 2);
      cursor.movePosition(QTextCursor::Left);
  
      cursor.insertTable(3, 3);
      QCOMPARE(cursor.position(), 2);
  
      cursor.movePosition(QTextCursor::Down);
      QCOMPARE(cursor.position(), 5);
  
      cursor.movePosition(QTextCursor::Right);
      QCOMPARE(cursor.position(), 6);
  
      cursor.movePosition(QTextCursor::Up);
      QCOMPARE(cursor.position(), 3);
  
      cursor.movePosition(QTextCursor::Right);
      QCOMPARE(cursor.position(), 4);
  
      cursor.movePosition(QTextCursor::Right);
      QCOMPARE(cursor.position(), 5);
  
      cursor.movePosition(QTextCursor::Up);
      QCOMPARE(cursor.position(), 2);
  
      cursor.movePosition(QTextCursor::Up);
      QCOMPARE(cursor.position(), 0);
  
  }
  
  void tst_QTextCursor::selectionsInTable()
  {
      QTextTable *table = cursor.insertTable(3, 3);
      table->cellAt(0, 0).firstCursorPosition().insertText("A a"); // first = 1
      table->cellAt(0, 1).firstCursorPosition().insertText("B b"); // first = 5
      table->cellAt(0, 2).firstCursorPosition().insertText("C c"); // first = 9
      table->cellAt(1, 0).firstCursorPosition().insertText("D d"); // first = 13
      table->cellAt(1, 1).firstCursorPosition().insertText("E e"); // first = 17
      table->cellAt(1, 2).firstCursorPosition().insertText("F f"); // first = 21
      table->cellAt(2, 0).firstCursorPosition().insertText("G g"); // first = 25
      table->cellAt(2, 1).firstCursorPosition().insertText("H h"); // first = 29
      table->cellAt(2, 2).firstCursorPosition().insertText("I i"); // first = 33
  
      cursor = table->cellAt(0, 0).lastCursorPosition();
      QCOMPARE(cursor.position(), 4);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor) == false);
      QCOMPARE(cursor.position(), 1);
  
      cursor = table->cellAt(1, 0).lastCursorPosition();
      QCOMPARE(cursor.position(), 16);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor) == false);
      QCOMPARE(cursor.position(), 13);
  
      cursor = table->cellAt(0, 2).firstCursorPosition();
      QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor) == false);
  
      cursor = table->cellAt(1, 2).firstCursorPosition();
      QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor));
      QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor) == false);
  
      // Next let's test selecting entire cells one at a time
      cursor = table->cellAt(0, 0).firstCursorPosition();
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 5);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 9);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 13);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 17);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 21);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 25);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 29);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 33);
      QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor) == false);
  
      // And now lets walk all the way back
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 29);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 25);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 21);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 17);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 13);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 9);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 5);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor));
      QCOMPARE(cursor.position(), 1);
      QVERIFY(cursor.movePosition(QTextCursor::PreviousCell, QTextCursor::KeepAnchor) == false);
  
      QTextCursor::MoveOperation leftMovements[5] = {
            QTextCursor::PreviousBlock
          , QTextCursor::PreviousCharacter
          , QTextCursor::PreviousWord
          , QTextCursor::Left
          , QTextCursor::WordLeft
      };
  
      QTextCursor::MoveOperation rightMovements[5] = {
          QTextCursor::NextBlock
          , QTextCursor::NextCharacter
          , QTextCursor::NextWord
          , QTextCursor::Right
          , QTextCursor::WordRight
      };
  
      for (int i = 0; i < 5; ++i) {
          QTextCursor::MoveOperation left = leftMovements[i];
          QTextCursor::MoveOperation right = rightMovements[i];
  
          // Lets walk circle around anchor placed at 1,1 using up, down, left and right
          cursor = table->cellAt(1, 1).firstCursorPosition();
          QCOMPARE(cursor.position(), 17);
          QVERIFY(cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 18); // First right should not jump more than one char
          QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 21); // Lets jump to the next cell
          QVERIFY(cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 33);
          QVERIFY(cursor.movePosition(left, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 29);
          QVERIFY(cursor.movePosition(left, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 25);
          QVERIFY(cursor.movePosition(QTextCursor::Up, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 13);
          QVERIFY(cursor.movePosition(QTextCursor::Up, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 1);
          QVERIFY(cursor.movePosition(right, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 5);
          QVERIFY(cursor.movePosition(right, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 9);
          QVERIFY(cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 21);
  
          // Lets walk to the side 2 cells and back, first right
          cursor = table->cellAt(0, 0).firstCursorPosition();
          QVERIFY(cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 5); // Lets jump to the next cell
          QVERIFY(cursor.movePosition(right, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 9);
          QVERIFY(cursor.movePosition(left, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 5);
          QVERIFY(cursor.movePosition(left, QTextCursor::KeepAnchor));
          QVERIFY(cursor.position() < 5);
  
          // Then left
          cursor = table->cellAt(0, 2).firstCursorPosition();
          QCOMPARE(cursor.position(), 9);
          QVERIFY(cursor.movePosition(left, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 5); // A single left should do
          QVERIFY(cursor.movePosition(left, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 1);
          QVERIFY(cursor.movePosition(right, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 5);
          QVERIFY(cursor.movePosition(right, QTextCursor::KeepAnchor));
          QCOMPARE(cursor.position(), 9);
      }
  }
  
  void tst_QTextCursor::selectedText()
  {
      cursor.insertText("Hello World");
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
  
      QCOMPARE(cursor.selectedText(), QString("Hello World"));
  }
  
  void tst_QTextCursor::insertBlockShouldRemoveSelection()
  {
      cursor.insertText("Hello World");
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
  
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectedText(), QString("Hello"));
  
      cursor.insertBlock();
  
      QVERIFY(!cursor.hasSelection());
      QCOMPARE(doc->toPlainText().indexOf("Hello"), -1);
  }
  
  void tst_QTextCursor::insertBlockShouldRemoveSelection2()
  {
      cursor.insertText("Hello World");
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
  
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectedText(), QString("Hello"));
  
      QTextBlockFormat fmt = cursor.blockFormat();
      cursor.insertBlock(fmt);
  
      QVERIFY(!cursor.hasSelection());
      QCOMPARE(doc->toPlainText().indexOf("Hello"), -1);
  }
  
  void tst_QTextCursor::mergeCellShouldUpdateSelection()
  {
      QTextTable *table = cursor.insertTable(4, 4);
      cursor.setPosition(table->cellAt(0, 0).firstPosition());
      cursor.setPosition(table->cellAt(3, 0).firstPosition(), QTextCursor::KeepAnchor); // aka bottom left
      int firstRow, numRows, firstColumn, numColumns;
      cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
      QCOMPARE(firstRow, 0);
      QCOMPARE(numRows, 4);
      QCOMPARE(firstColumn, 0);
      QCOMPARE(numColumns, 1);
  
      table->removeColumns(firstColumn, numColumns);
  
      QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition());
      QCOMPARE(cursor.position(), table->cellAt(0, 0).firstPosition());
      QCOMPARE(cursor.position(), cursor.anchor()); // empty. I don't really care where it ends up.
  
      // prepare for another test with multiple cursors.
      // note we have a 4 rows, 3 cols table now.
      cursor.setPosition(table->cellAt(0, 0).firstPosition());
      cursor.setPosition(table->cellAt(0, 2).firstPosition(), QTextCursor::KeepAnchor);
  
      // now create a selection of a whole row.
      QTextCursor c2 = table->cellAt(2, 0).firstCursorPosition();
      c2.setPosition(table->cellAt(2, 2).firstPosition(), QTextCursor::KeepAnchor);
  
      // just for good measure, another one for a block of cells.
      QTextCursor c3 = table->cellAt(2, 1).firstCursorPosition();
      c3.setPosition(table->cellAt(3, 2).firstPosition(), QTextCursor::KeepAnchor);
  
      table->removeRows(2, 1);
  
      QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition());
      QCOMPARE(cursor.position(), table->cellAt(0, 2).firstPosition());
  
      QCOMPARE(c2.position(), c2.anchor()); // empty. I don't really care where it ends up.
  
      QCOMPARE(c3.anchor(), table->cellAt(2, 1).firstPosition());
      QCOMPARE(c3.position(), table->cellAt(2, 2).firstPosition());
  
  
      // prepare for another test where we remove a column
      // note we have a 3 rows, 3 cols table now.
      cursor.setPosition(table->cellAt(0, 0).firstPosition());
      cursor.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor);
  
      c2.setPosition(table->cellAt(0, 1).firstPosition());
      c2.setPosition(table->cellAt(2, 2).firstPosition(), QTextCursor::KeepAnchor);
  
      table->removeColumns(1, 1);
  
      QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition());
      QCOMPARE(cursor.position(), table->cellAt(2, 0).firstPosition());
  
      QCOMPARE(c2.anchor(), table->cellAt(0, 1).firstPosition());
      QCOMPARE(c2.position(), table->cellAt(2, 1).firstPosition());
  
      // test for illegal cursor positions.
      // note we have a 3 rows, 2 cols table now.
      cursor.setPosition(table->cellAt(2, 0).firstPosition());
      cursor.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor);
  
      c2.setPosition(table->cellAt(0, 0).firstPosition());
      c2.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor);
  
      c3.setPosition(table->cellAt(2, 1).firstPosition());
  
      table->removeRows(2, 1);
  
      QCOMPARE(cursor.anchor(), table->cellAt(1, 1).lastPosition()+1);
      QCOMPARE(cursor.position(), cursor.anchor());
  
      QCOMPARE(c2.anchor(), table->cellAt(0, 0).firstPosition());
      QCOMPARE(c2.position(), table->cellAt(1, 1).firstPosition());
  
      QCOMPARE(c3.anchor(), table->cellAt(1, 1).firstPosition());
      QCOMPARE(c3.position(), table->cellAt(1, 1).firstPosition());
  }
  
  void tst_QTextCursor::joinPreviousEditBlock()
  {
      cursor.beginEditBlock();
      cursor.insertText("Hello");
      cursor.insertText("World");
      cursor.endEditBlock();
      QVERIFY(doc->toPlainText().startsWith("HelloWorld"));
  
      cursor.joinPreviousEditBlock();
      cursor.insertText("Hey");
      cursor.endEditBlock();
      QVERIFY(doc->toPlainText().startsWith("HelloWorldHey"));
  
      doc->undo();
      QVERIFY(!doc->toPlainText().contains("HelloWorldHey"));
  }
  
  void tst_QTextCursor::setBlockFormatInTable()
  {
      // someone reported this on qt4-preview-feedback
      QTextBlockFormat fmt;
      fmt.setBackground(Qt::blue);
      cursor.setBlockFormat(fmt);
  
      QTextTable *table = cursor.insertTable(2, 2);
      cursor = table->cellAt(0, 0).firstCursorPosition();
      fmt.setBackground(Qt::red);
      cursor.setBlockFormat(fmt);
  
      cursor.movePosition(QTextCursor::Start);
      QCOMPARE(cursor.blockFormat().background().color(), QColor(Qt::blue));
  }
  
  void tst_QTextCursor::blockCharFormat2()
  {
      QTextCharFormat fmt;
      fmt.setForeground(Qt::green);
      cursor.mergeBlockCharFormat(fmt);
  
      fmt.setForeground(Qt::red);
  
      cursor.insertText("Test", fmt);
      cursor.movePosition(QTextCursor::Start);
      cursor.insertText("Red");
      cursor.movePosition(QTextCursor::PreviousCharacter);
      QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::red));
  }
  
  void tst_QTextCursor::blockCharFormat3()
  {
      QVERIFY(cursor.atBlockStart());
      QVERIFY(cursor.atBlockEnd());
      QVERIFY(cursor.atStart());
  
      QTextCharFormat fmt;
      fmt.setForeground(Qt::green);
      cursor.setBlockCharFormat(fmt);
      cursor.insertText("Test");
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::NextCharacter);
      const QColor red(Qt::red);
      const QColor green(Qt::green);
      QCOMPARE(cursor.charFormat().foreground().color(), green);
  
      cursor.movePosition(QTextCursor::Start);
      QCOMPARE(cursor.charFormat().foreground().color(), green);
  
      fmt.setForeground(Qt::red);
      cursor.setBlockCharFormat(fmt);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), red);
  
      cursor.movePosition(QTextCursor::End);
      cursor.movePosition(QTextCursor::Start);
      QCOMPARE(cursor.charFormat().foreground().color(), green);
  
      cursor.insertText("Test");
      QCOMPARE(cursor.charFormat().foreground().color(), green);
  
      cursor.select(QTextCursor::Document);
      cursor.removeSelectedText();
      QVERIFY(cursor.atBlockStart());
      QVERIFY(cursor.atBlockEnd());
      QVERIFY(cursor.atStart());
  
      cursor.insertText("Test");
      QCOMPARE(cursor.charFormat().foreground().color(), red);
  }
  
  void tst_QTextCursor::blockCharFormat()
  {
      QTextCharFormat fmt;
      fmt.setForeground(Qt::blue);
      cursor.insertBlock(QTextBlockFormat(), fmt);
      cursor.insertText("Hm");
  
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::blue));
  
      fmt.setForeground(Qt::red);
  
      cursor.setBlockCharFormat(fmt);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::red));
  }
  
  void tst_QTextCursor::blockCharFormatOnSelection()
  {
      QTextCharFormat fmt;
      fmt.setForeground(Qt::blue);
      cursor.insertBlock(QTextBlockFormat(), fmt);
  
      fmt.setForeground(Qt::green);
      cursor.insertText("Hm", fmt);
  
      fmt.setForeground(Qt::red);
      cursor.insertBlock(QTextBlockFormat(), fmt);
      cursor.insertText("Ah");
  
      fmt.setForeground(Qt::white);
      cursor.insertBlock(QTextBlockFormat(), fmt);
      cursor.insertText("bleh");
  
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::blue));
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::red));
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::white));
  
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::NextBlock);
      cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
  
      fmt.setForeground(Qt::cyan);
      cursor.setBlockCharFormat(fmt);
  
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::cyan));
  
      cursor.movePosition(QTextCursor::Right);
      cursor.movePosition(QTextCursor::Right);
      QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::green));
  
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::cyan));
  
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.blockCharFormat().foreground().color(), QColor(Qt::white));
  }
  
  void tst_QTextCursor::anchorInitialized1()
  {
      cursor.insertBlock();
      cursor = QTextCursor(cursor.block());
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.anchor(), 1);
      QCOMPARE(cursor.selectionStart(), 1);
      QCOMPARE(cursor.selectionEnd(), 1);
  }
  
  void tst_QTextCursor::anchorInitialized2()
  {
      cursor.insertBlock();
      cursor = QTextCursorPrivate::fromPosition(cursor.block().docHandle(), 1);
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.anchor(), 1);
      QCOMPARE(cursor.selectionStart(), 1);
      QCOMPARE(cursor.selectionEnd(), 1);
  }
  
  void tst_QTextCursor::anchorInitialized3()
  {
      QTextFrame *frame = cursor.insertFrame(QTextFrameFormat());
      cursor = QTextCursor(frame);
      QCOMPARE(cursor.position(), 1);
      QCOMPARE(cursor.anchor(), 1);
      QCOMPARE(cursor.selectionStart(), 1);
      QCOMPARE(cursor.selectionEnd(), 1);
  }
  
  void tst_QTextCursor::selectWord()
  {
      cursor.insertText("first second     third");
      cursor.insertBlock();
      cursor.insertText("words in second paragraph");
  
      cursor.setPosition(9);
      cursor.select(QTextCursor::WordUnderCursor);
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectionStart(), 6);
      QCOMPARE(cursor.selectionEnd(), 12);
  
      cursor.setPosition(5);
      cursor.select(QTextCursor::WordUnderCursor);
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectionStart(), 0);
      QCOMPARE(cursor.selectionEnd(), 5);
  
      cursor.setPosition(6);
      cursor.select(QTextCursor::WordUnderCursor);
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectionStart(), 6);
      QCOMPARE(cursor.selectionEnd(), 12);
  
      cursor.setPosition(14);
      cursor.select(QTextCursor::WordUnderCursor);
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectionStart(), 6);
      QCOMPARE(cursor.selectionEnd(), 12);
  
      cursor.movePosition(QTextCursor::Start);
      cursor.select(QTextCursor::WordUnderCursor);
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectionStart(), 0);
      QCOMPARE(cursor.selectionEnd(), 5);
  
      cursor.movePosition(QTextCursor::EndOfBlock);
      cursor.select(QTextCursor::WordUnderCursor);
      QVERIFY(cursor.hasSelection());
      QCOMPARE(cursor.selectionStart(), 17);
      QCOMPARE(cursor.selectionEnd(), 22);
  }
  
  void tst_QTextCursor::selectWordWithSeparators_data()
  {
      QTest::addColumn<QString>("text");
      QTest::addColumn<int>("initialPosition");
      QTest::addColumn<QString>("expectedSelectedText");
  
      QTest::newRow("dereference") << QString::fromLatin1("foo->bar()") << 1 << QString::fromLatin1("foo");
      QTest::newRow("funcsignature") << QString::fromLatin1("bar(int x);") << 1 << QString::fromLatin1("bar");
      QTest::newRow("def") << QString::fromLatin1("foo *f;") << 1 << QString::fromLatin1("foo");
  }
  
  void tst_QTextCursor::selectWordWithSeparators()
  {
      QFETCH(QString, text);
      QFETCH(int, initialPosition);
      QFETCH(QString, expectedSelectedText);
  
      cursor.insertText(text);
      cursor.setPosition(initialPosition);
      cursor.select(QTextCursor::WordUnderCursor);
  
      QCOMPARE(cursor.selectedText(), expectedSelectedText);
  }
  
  void tst_QTextCursor::startOfWord()
  {
      cursor.insertText("first     second");
      cursor.setPosition(7);
      cursor.movePosition(QTextCursor::StartOfWord);
      QCOMPARE(cursor.position(), 0);
  }
  
  void tst_QTextCursor::selectBlock()
  {
      cursor.insertText("foobar");
      QTextBlockFormat blockFmt;
      blockFmt.setAlignment(Qt::AlignHCenter);
      cursor.insertBlock(blockFmt);
      cursor.insertText("blah");
      cursor.insertBlock(QTextBlockFormat());
  
      cursor.movePosition(QTextCursor::PreviousBlock);
      QCOMPARE(cursor.block().text(), QString("blah"));
  
      cursor.select(QTextCursor::BlockUnderCursor);
      QVERIFY(cursor.hasSelection());
  
      QTextDocumentFragment fragment(cursor);
      doc->clear();
      cursor.insertFragment(fragment);
      QCOMPARE(blockCount(), 2);
  
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.blockFormat().alignment(), Qt::AlignHCenter);
      QCOMPARE(cursor.block().text(), QString("blah"));
  }
  
  void tst_QTextCursor::selectVisually()
  {
      cursor.insertText("Foo\nlong line which is probably going to be cut in two when shown in a widget\nparagraph 3\n");
  
      cursor.setPosition(6); // somewhere in the long paragraph.
      cursor.select(QTextCursor::LineUnderCursor);
      // since we are not yet laid-out, we expect the whole paragraph to be selected.
      QCOMPARE(cursor.position(), 77);
      QCOMPARE(cursor.anchor(), 4);
  }
  
  void tst_QTextCursor::insertText()
  {
      QString txt = "Foo\nBar\r\nMeep";
      txt += QChar::LineSeparator;
      txt += "Baz";
      txt += QChar::ParagraphSeparator;
      txt += "yoyodyne";
      cursor.insertText(txt);
      QCOMPARE(blockCount(), 4);
      cursor.movePosition(QTextCursor::Start);
      QCOMPARE(cursor.block().text(), QString("Foo"));
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.block().text(), QString("Bar"));
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.block().text(), QString(QString("Meep") + QChar(QChar::LineSeparator) + QString("Baz")));
      cursor.movePosition(QTextCursor::NextBlock);
      QCOMPARE(cursor.block().text(), QString("yoyodyne"));
  }
  
  void tst_QTextCursor::insertFragmentShouldUseCurrentCharFormat()
  {
      QTextDocumentFragment fragment = QTextDocumentFragment::fromPlainText("Hello World");
      QTextCharFormat fmt;
      fmt.setFontUnderline(true);
  
      cursor.clearSelection();
      cursor.setCharFormat(fmt);
      cursor.insertFragment(fragment);
      cursor.movePosition(QTextCursor::Start);
      cursor.movePosition(QTextCursor::NextCharacter);
      QCOMPARE(cursor.charFormat(), fmt);
  }
  
  int tst_QTextCursor::blockCount()
  {
      int cnt = 0;
      for (QTextBlock blk = doc->begin(); blk.isValid(); blk = blk.next())
          ++cnt;
      return cnt;
  }
  
  void tst_QTextCursor::endOfLine()
  {
      doc->setPageSize(QSizeF(100000, INT_MAX));
  
      QString text("First Line    \nSecond Line  ");
      text.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
      cursor.insertText(text);
  
      // ensure layouted
      doc->documentLayout()->documentSize();
  
      cursor.movePosition(QTextCursor::Start);
  
      QCOMPARE(cursor.block().layout()->lineCount(), 2);
  
      cursor.movePosition(QTextCursor::EndOfLine);
      QCOMPARE(cursor.position(), 14);
      cursor.movePosition(QTextCursor::NextCharacter);
      QCOMPARE(cursor.position(), 15);
      cursor.movePosition(QTextCursor::EndOfLine);
      QCOMPARE(cursor.position(), 28);
  }
  
  class CursorListener : public QObject
  {
      Q_OBJECT
  public:
      CursorListener(QTextCursor *_cursor) : lastRecordedPosition(-1), lastRecordedAnchor(-1), recordingCount(0), cursor(_cursor) {}
  
      int lastRecordedPosition;
      int lastRecordedAnchor;
      int recordingCount;
  
  public slots:
      void recordCursorPosition()
      {
          lastRecordedPosition = cursor->position();
          lastRecordedAnchor = cursor->anchor();
          ++recordingCount;
      }
  
      void selectAllContents()
      {
          // Only test the first time
          if (!recordingCount) {
              recordingCount++;
              cursor->select(QTextCursor::Document);
              lastRecordedPosition = cursor->position();
              lastRecordedAnchor = cursor->anchor();
          }
      }
  
  private:
      QTextCursor *cursor;
  };
  
  void tst_QTextCursor::editBlocksDuringRemove()
  {
      CursorListener listener(&cursor);
  
      cursor.insertText("Hello World");
      cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);
      QCOMPARE(cursor.selectedText(), QString("Hello World"));
  
      connect(doc, SIGNAL(contentsChanged()), &listener, SLOT(recordCursorPosition()));
      listener.recordingCount = 0;
      cursor.deleteChar();
  
      QCOMPARE(listener.recordingCount, 1);
      QCOMPARE(listener.lastRecordedPosition, 0);
      QCOMPARE(listener.lastRecordedAnchor, 0);
  
      QVERIFY(doc->toPlainText().isEmpty());
  }
  
  void tst_QTextCursor::selectAllDuringRemove()
  {
      CursorListener listener(&cursor);
  
      cursor.insertText("Hello World");
      cursor.movePosition(QTextCursor::End);
  
      connect(doc, SIGNAL(contentsChanged()), &listener, SLOT(selectAllContents()));
      listener.recordingCount = 0;
      QTextCursor localCursor = cursor;
      localCursor.deletePreviousChar();
  
      QCOMPARE(listener.lastRecordedPosition, 10);
      QCOMPARE(listener.lastRecordedAnchor, 0);
  }
  
  void tst_QTextCursor::update_data()
  {
      QTest::addColumn<QString>("text");
      QTest::addColumn<int>("position");
      QTest::addColumn<int>("anchor");
      QTest::addColumn<int>("modifyPosition");
      QTest::addColumn<int>("modifyAnchor");
      QTest::addColumn<QString>("insertText");
      QTest::addColumn<int>("expectedPosition");
      QTest::addColumn<int>("expectedAnchor");
  
      QString text("Hello big world");
      int charsToDelete = 3;
      QTest::newRow("removeInsideSelection")
          << text
          << /*position*/ 0
          << /*anchor*/ text.length()
          // delete 'big'
          << 6
          << 6 + charsToDelete
          << QString() // don't insert anything, just remove
          << /*expectedPosition*/ 0
          << /*expectedAnchor*/ text.length() - charsToDelete
          ;
  
      text = "Hello big world";
      charsToDelete = 3;
      QTest::newRow("removeInsideSelectionWithSwappedAnchorAndPosition")
          << text
          << /*position*/ text.length()
          << /*anchor*/ 0
          // delete 'big'
          << 6
          << 6 + charsToDelete
          << QString() // don't insert anything, just remove
          << /*expectedPosition*/ text.length() - charsToDelete
          << /*expectedAnchor*/ 0
          ;
  
  
      text = "Hello big world";
      charsToDelete = 3;
      QString textToInsert("small");
      QTest::newRow("replaceInsideSelection")
          << text
          << /*position*/ 0
          << /*anchor*/ text.length()
          // delete 'big' ...
          << 6
          << 6 + charsToDelete
          << textToInsert // ... and replace 'big' with 'small'
          << /*expectedPosition*/ 0
          << /*expectedAnchor*/ text.length() - charsToDelete + textToInsert.length()
          ;
  
      text = "Hello big world";
      charsToDelete = 3;
      textToInsert = "small";
      QTest::newRow("replaceInsideSelectionWithSwappedAnchorAndPosition")
          << text
          << /*position*/ text.length()
          << /*anchor*/ 0
          // delete 'big' ...
          << 6
          << 6 + charsToDelete
          << textToInsert // ... and replace 'big' with 'small'
          << /*expectedPosition*/ text.length() - charsToDelete + textToInsert.length()
          << /*expectedAnchor*/ 0
          ;
  
  
      text = "Hello big world";
      charsToDelete = 3;
      QTest::newRow("removeBeforeSelection")
          << text
          << /*position*/ text.length() - 5
          << /*anchor*/ text.length()
          // delete 'big'
          << 6
          << 6 + charsToDelete
          << QString() // don't insert anything, just remove
          << /*expectedPosition*/ text.length() - 5 - charsToDelete
          << /*expectedAnchor*/ text.length() - charsToDelete
          ;
  
      text = "Hello big world";
      charsToDelete = 3;
      QTest::newRow("removeAfterSelection")
          << text
          << /*position*/ 0
          << /*anchor*/ 4
          // delete 'big'
          << 6
          << 6 + charsToDelete
          << QString() // don't insert anything, just remove
          << /*expectedPosition*/ 0
          << /*expectedAnchor*/ 4
          ;
  
  }
  
  void tst_QTextCursor::update()
  {
      QFETCH(QString, text);
  
      doc->setPlainText(text);
  
      QFETCH(int, position);
      QFETCH(int, anchor);
  
      cursor.setPosition(anchor);
      cursor.setPosition(position, QTextCursor::KeepAnchor);
  
      QCOMPARE(cursor.position(), position);
      QCOMPARE(cursor.anchor(), anchor);
  
      QFETCH(int, modifyPosition);
      QFETCH(int, modifyAnchor);
  
      QTextCursor modifyCursor = cursor;
      modifyCursor.setPosition(modifyAnchor);
      modifyCursor.setPosition(modifyPosition, QTextCursor::KeepAnchor);
  
      QCOMPARE(modifyCursor.position(), modifyPosition);
      QCOMPARE(modifyCursor.anchor(), modifyAnchor);
  
      QFETCH(QString, insertText);
      modifyCursor.insertText(insertText);
  
      QFETCH(int, expectedPosition);
      QFETCH(int, expectedAnchor);
  
      QCOMPARE(cursor.position(), expectedPosition);
      QCOMPARE(cursor.anchor(), expectedAnchor);
  }
  
  void tst_QTextCursor::disallowSettingObjectIndicesOnCharFormats()
  {
      QTextCharFormat fmt;
      fmt.setObjectIndex(42);
      cursor.insertText("Hey", fmt);
      QCOMPARE(cursor.charFormat().objectIndex(), -1);
  
      cursor.select(QTextCursor::Document);
      cursor.mergeCharFormat(fmt);
      QCOMPARE(doc->begin().begin().fragment().charFormat().objectIndex(), -1);
  
      cursor.select(QTextCursor::Document);
      cursor.setCharFormat(fmt);
      QCOMPARE(doc->begin().begin().fragment().charFormat().objectIndex(), -1);
  
      cursor.setBlockCharFormat(fmt);
      QCOMPARE(cursor.blockCharFormat().objectIndex(), -1);
  
      cursor.movePosition(QTextCursor::End);
      cursor.insertBlock(QTextBlockFormat(), fmt);
      QCOMPARE(cursor.blockCharFormat().objectIndex(), -1);
  
      doc->clear();
  
      QTextTable *table = cursor.insertTable(1, 1);
      cursor.select(QTextCursor::Document);
      cursor.setCharFormat(fmt);
  
      cursor = table->cellAt(0, 0).firstCursorPosition();
      QVERIFY(!cursor.isNull());
      QCOMPARE(cursor.blockCharFormat().objectIndex(), table->objectIndex());
  }
  
  void tst_QTextCursor::blockAndColumnNumber()
  {
      QCOMPARE(QTextCursor().columnNumber(), 0);
      QCOMPARE(QTextCursor().blockNumber(), 0);
  
      QCOMPARE(cursor.columnNumber(), 0);
      QCOMPARE(cursor.blockNumber(), 0);
      cursor.insertText("Hello");
      QCOMPARE(cursor.columnNumber(), 5);
      QCOMPARE(cursor.blockNumber(), 0);
  
      cursor.insertBlock();
      QCOMPARE(cursor.columnNumber(), 0);
      QCOMPARE(cursor.blockNumber(), 1);
      cursor.insertText("Blah");
      QCOMPARE(cursor.blockNumber(), 1);
  
      // trigger a layout
      doc->documentLayout();
  
      cursor.insertBlock();
      QCOMPARE(cursor.columnNumber(), 0);
      QCOMPARE(cursor.blockNumber(), 2);
      cursor.insertText("Test");
      QCOMPARE(cursor.columnNumber(), 4);
      QCOMPARE(cursor.blockNumber(), 2);
      cursor.insertText(QString(QChar(QChar::LineSeparator)));
      QCOMPARE(cursor.columnNumber(), 0);
      QCOMPARE(cursor.blockNumber(), 2);
      cursor.insertText("A");
      QCOMPARE(cursor.columnNumber(), 1);
      QCOMPARE(cursor.blockNumber(), 2);
  }
  
  void tst_QTextCursor::movePositionEndOfLine()
  {
      cursor.insertText("blah\nblah\n");
      // Select part of the second line ("la")
      cursor.setPosition(6);
      cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
      QCOMPARE(cursor.selectedText(), QLatin1String("la"));
  
      // trigger a layout
      doc->documentLayout();
  
      // Remove "la" and append "something" to the end in one undo operation
      cursor.beginEditBlock();
      cursor.removeSelectedText();
      QTextCursor c2(doc);
      c2.setPosition(7);
      c2.insertText("foo"); // append to doc without touching the cursor.
  
      QCOMPARE(cursor.position(), 6);
      cursor.movePosition(QTextCursor::EndOfLine); // in an edit block visual movement is moved to the end of the paragraph
      QCOMPARE(cursor.position(), 10);
      cursor.endEditBlock();
  }
  
  void tst_QTextCursor::clearCells()
  {
      QTextTable *table = cursor.insertTable(3, 5);
      cursor.setPosition(table->cellAt(0,0).firstPosition()); // select cell 1 and cell 2
      cursor.setPosition(table->cellAt(0,1).firstPosition(), QTextCursor::KeepAnchor);
      cursor.deleteChar(); // should clear the cells, and not crash ;)
  }
  
  void tst_QTextCursor::task244408_wordUnderCursor_data()
  {
      QTest::addColumn<QString>("input");
      QTest::addColumn<QString>("expected");
      QTest::newRow("trailingSpace") << QString::fromLatin1("foo ") << QString::fromLatin1("");
      QTest::newRow("noTrailingSpace") << QString::fromLatin1("foo") << QString::fromLatin1("foo");
  }
  
  void tst_QTextCursor::task244408_wordUnderCursor()
  {
      QFETCH(QString, input);
      QFETCH(QString, expected);
      cursor.insertText(input);
      cursor.movePosition(QTextCursor::End);
      cursor.select(QTextCursor::WordUnderCursor);
      QCOMPARE(cursor.selectedText(), expected);
  }
  
  void tst_QTextCursor::adjustCursorsOnInsert()
  {
      cursor.insertText("Some text before ");
      int posBefore = cursor.position();
      cursor.insertText("selected text");
      int posAfter = cursor.position();
      cursor.insertText(" some text afterwards");
  
      QTextCursor selection = cursor;
      selection.setPosition(posBefore);
      selection.setPosition(posAfter, QTextCursor::KeepAnchor);
  
      cursor.setPosition(posBefore-1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.anchor(), posBefore+1);
      QCOMPARE(selection.position(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posBefore);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.anchor(), posBefore+1);
      QCOMPARE(selection.position(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posBefore+1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.anchor(), posBefore);
      QCOMPARE(selection.position(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posAfter-1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.anchor(), posBefore);
      QCOMPARE(selection.position(), posAfter+1);
      doc->undo();
  
      selection.setKeepPositionOnInsert(true);
      cursor.setPosition(posAfter);
      cursor.insertText(QLatin1String("x"));
      selection.setKeepPositionOnInsert(false);
      QCOMPARE(selection.anchor(), posBefore);
      QCOMPARE(selection.position(), posAfter);
      doc->undo();
  
      cursor.setPosition(posAfter+1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.anchor(), posBefore);
      QCOMPARE(selection.position(), posAfter);
      doc->undo();
  
      selection.setPosition(posAfter);
      selection.setPosition(posBefore, QTextCursor::KeepAnchor);
  
      cursor.setPosition(posBefore-1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.position(), posBefore+1);
      QCOMPARE(selection.anchor(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posBefore);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.position(), posBefore+1);
      QCOMPARE(selection.anchor(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posBefore+1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.position(), posBefore);
      QCOMPARE(selection.anchor(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posAfter-1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.position(), posBefore);
      QCOMPARE(selection.anchor(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posAfter);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.position(), posBefore);
      QCOMPARE(selection.anchor(), posAfter+1);
      doc->undo();
  
      cursor.setPosition(posAfter+1);
      cursor.insertText(QLatin1String("x"));
      QCOMPARE(selection.position(), posBefore);
      QCOMPARE(selection.anchor(), posAfter);
      doc->undo();
  
  }
  void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo()
  {
      cursor.insertText("AAAABBBBCCCCDDDD");
      cursor.setPosition(12);
      int cursorPositionBefore = cursor.position();
      cursor.beginEditBlock();
      cursor.insertText("*");
      cursor.setPosition(8);
      cursor.insertText("*");
      cursor.setPosition(4);
      cursor.insertText("*");
      cursor.setPosition(0);
      cursor.insertText("*");
      int cursorPositionAfter = cursor.position();
      cursor.endEditBlock();
  
      QCOMPARE(doc->toPlainText(), QLatin1String("*AAAA*BBBB*CCCC*DDDD"));
      QCOMPARE(12, cursorPositionBefore);
      QCOMPARE(1, cursorPositionAfter);
  
      doc->undo(&cursor);
      QCOMPARE(doc->toPlainText(), QLatin1String("AAAABBBBCCCCDDDD"));
      QCOMPARE(cursor.position(), cursorPositionBefore);
      doc->redo(&cursor);
      QCOMPARE(doc->toPlainText(), QLatin1String("*AAAA*BBBB*CCCC*DDDD"));
      QCOMPARE(cursor.position(), cursorPositionAfter);
  }
  
  void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo2()
  {
      cursor.insertText("AAAABBBB");
      int cursorPositionBefore = cursor.position();
      cursor.setPosition(0, QTextCursor::KeepAnchor);
      cursor.beginEditBlock();
      cursor.removeSelectedText();
      cursor.insertText("AAAABBBBCCCCDDDD");
      cursor.endEditBlock();
      doc->undo(&cursor);
      QCOMPARE(doc->toPlainText(), QLatin1String("AAAABBBB"));
      QCOMPARE(cursor.position(), cursorPositionBefore);
  
      cursor.insertText("CCCC");
      QCOMPARE(doc->toPlainText(), QLatin1String("AAAABBBBCCCC"));
  
      cursorPositionBefore = cursor.position();
      cursor.setPosition(0, QTextCursor::KeepAnchor);
      cursor.beginEditBlock();
      cursor.removeSelectedText();
      cursor.insertText("AAAABBBBCCCCDDDD");
      cursor.endEditBlock();
  
      /* this undo now implicitely reinserts two segments, first "CCCCC", then
         "AAAABBBB". The test ensures that the two are combined in order to
         reconstruct the correct cursor position */
      doc->undo(&cursor);
  
  
      QCOMPARE(doc->toPlainText(), QLatin1String("AAAABBBBCCCC"));
      QCOMPARE(cursor.position(), cursorPositionBefore);
  }
  
  void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo3()
  {
      // verify that it's the position of the beginEditBlock that counts, and not the last edit position
      cursor.insertText("AAAABBBB");
      int cursorPositionBefore = cursor.position();
      cursor.beginEditBlock();
      cursor.setPosition(4);
      QVERIFY(cursor.position() != cursorPositionBefore);
      cursor.insertText("*");
      cursor.endEditBlock();
      QCOMPARE(cursor.position(), 5);
      doc->undo(&cursor);
      QCOMPARE(cursor.position(), cursorPositionBefore);
  }
  
  void tst_QTextCursor::joinNonEmptyRemovedBlockUserState()
  {
      cursor.insertText("Hello");
      cursor.insertBlock();
      cursor.insertText("World");
      cursor.block().setUserState(10);
  
      cursor.movePosition(QTextCursor::EndOfBlock);
      cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::KeepAnchor);
      cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
      cursor.removeSelectedText();
  
      QCOMPARE(cursor.block().userState(), 10);
  }
  
  QTEST_MAIN(tst_QTextCursor)
  #include "tst_qtextcursor.moc"
  