1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 
43 #include <QtTest/QtTest>
44 
45 #include <limits.h>
46 
47 #include <q3textedit.h>
48 #include <q3textedit.h>
49 #include <qapplication.h>
50 #include <qclipboard.h>
51 #include <qimage.h>
52 #include <private/q3richtext_p.h>
53 
54 #ifdef Q_WS_MAC
55 #include <Carbon/Carbon.h>
56 #endif
57 
58 //TESTED_CLASS=
59 //TESTED_FILES=
60 
61 class tst_Q3TextEdit : public QObject
62 {
63     Q_OBJECT
64 public:
65     tst_Q3TextEdit();
66     virtual ~tst_Q3TextEdit();
67 
68 
69 public slots:
70     void initTestCase();
71     void cleanupTestCase();
72 private slots:
73     void getSetCheck();
74     void redoAvailableEmitted( bool );
75     void undoAvailableEmitted( bool );
76     void copyAvailableEmitted( bool );
77 
78     void cursorPosition_data();
79     void cursorPosition();
80     void doKeyboardAction_data();
81     void doKeyboardAction();
82     void text();
83     void text_data();
84 
85     void insert();
86 
87     void keyClicks_data();
88     void keyClicks();
89 
90     //problem specific tests
91     void copyPaste();
92     void copyPaste_data();
93 
94     void setReadOnly();
95 
96     void find_data();
97     void find();
98     void findSC();
99     void cut();
100 
101     void clear();
102     void selectAll();
103     void getSelection_data();
104     void getSelection();
105 
106     void setCurrentFont();
107 
108     void undoRedo();
109 
110     void length_data();
111     void length();
112     void findBackwards();
113     void anchorTest();
114 
115 private:
116     bool nativeClipboardWorking();
117     Q3TextEdit *textEdit;
118     bool redoA, undoA, copyA;
119 
120 };
121 
nativeClipboardWorking()122 bool tst_Q3TextEdit::nativeClipboardWorking()
123 {
124 #ifdef Q_WS_MAC
125     PasteboardRef pasteboard;
126     OSStatus status = PasteboardCreate(0, &pasteboard);
127     if (status == noErr)
128         CFRelease(pasteboard);
129     return status == noErr;
130 #endif
131     return true;
132 }
133 
134 
135 
136 class My3TextEdit : public Q3TextEdit
137 {
138 public:
My3TextEdit()139     My3TextEdit() : Q3TextEdit() {}
setDocument(Q3TextDocument * doc)140     void setDocument(Q3TextDocument *doc) { Q3TextEdit::setDocument(doc); }
document()141     Q3TextDocument *document() { return Q3TextEdit::document(); }
142 };
143 
144 // Testing get/set functions
getSetCheck()145 void tst_Q3TextEdit::getSetCheck()
146 {
147     My3TextEdit obj1;
148     // int Q3TextEdit::maxLogLines()
149     // void Q3TextEdit::setMaxLogLines(int)
150     obj1.setMaxLogLines(0);
151     QCOMPARE(obj1.maxLogLines(), 0);
152     obj1.setMaxLogLines(INT_MIN);
153     QCOMPARE(obj1.maxLogLines(), -1);
154     obj1.setMaxLogLines(INT_MAX);
155     QCOMPARE(obj1.maxLogLines(), INT_MAX);
156 
157     // Q3TextDocument * Q3TextEdit::document()
158     // void Q3TextEdit::setDocument(Q3TextDocument *)
159     Q3TextDocument *var2 = new Q3TextDocument(0);
160     obj1.setDocument(var2);
161     QCOMPARE(obj1.document(), var2);
162     // Should've done as QTextEdit, and created a new document, if you setDocument(0).
163     // Unfortunately it doesn't, and we cannot change it.
164     obj1.setDocument((Q3TextDocument *)0);
165     QCOMPARE(obj1.document(), var2);
166     // delete var2; // No delete, since Q3TextEdit takes ownership
167 }
168 
169 typedef QList<int> IntList;
170 Q_DECLARE_METATYPE(IntList)
171 Q_DECLARE_METATYPE(Q3TextEdit::KeyboardAction)
172 
173 static const char *const bullet_xpm[] =
174     {
175         "11 11 5 1",
176         ". c None",
177         "b c #3100c5",
178         "# c #313062",
179         "c c #3189ff",
180         "a c #6265cd",
181         "...........",
182         "...####....",
183         ".a#bbbb#a..",
184         ".#ccbbbb#..",
185         "#bccbbbbb#.",
186         "#bbbbbbbb#.",
187         "#bbbbbbcb#.",
188         "#bbbbbccb#.",
189         ".#bbbccb#..",
190         ".a#bbbb#a..",
191         "...####...."
192     };
193 
tst_Q3TextEdit()194 tst_Q3TextEdit::tst_Q3TextEdit()
195 {
196 }
197 
~tst_Q3TextEdit()198 tst_Q3TextEdit::~tst_Q3TextEdit()
199 {
200 }
201 
initTestCase()202 void tst_Q3TextEdit::initTestCase()
203 {
204     textEdit = new Q3TextEdit( 0, "textEdit" );
205     textEdit->setFixedSize( 200, 200 );
206     textEdit->mimeSourceFactory()->setImage( "bullet", QImage( bullet_xpm ) );
207     qApp->setMainWidget( textEdit );
208     textEdit->show();
209 }
210 
cleanupTestCase()211 void tst_Q3TextEdit::cleanupTestCase()
212 {
213     delete textEdit;
214 }
215 
doKeyboardAction()216 void tst_Q3TextEdit::doKeyboardAction()
217 {
218     QFETCH( QString, text );
219     QFETCH( int, paragraph );
220     QFETCH( int, index );
221     QFETCH( Q3TextEdit::KeyboardAction, action );
222 
223     textEdit->setText( text );
224     textEdit->setCursorPosition( paragraph, index );
225     textEdit->doKeyboardAction( action );
226     QTEST( textEdit->text(), "final" );
227 }
228 
doKeyboardAction_data()229 void tst_Q3TextEdit::doKeyboardAction_data()
230 {
231     QTest::addColumn<QString>("text");
232     QTest::addColumn<int>("paragraph");
233     QTest::addColumn<int>("index");
234     QTest::addColumn<Q3TextEdit::KeyboardAction>("action");
235     QTest::addColumn<QString>("final");
236 
237     QTest::newRow( "Bush1" ) <<
238 	QString("Republicans understand the importance of bondage between mother and child. - Gov GWB")
239 			    << 0
240 			    << 49
241 			    << Q3TextEdit::ActionWordDelete
242 			    <<
243 	QString("Republicans understand the importance of bondage mother and child. - Gov GWB");
244 
245     QTest::newRow( "Bush2" ) <<
246 	QString("If we don't succeed, we run the risk of failure. ...George W. Bush, Jr.")
247 			    << 0
248 			    << 2
249 			    << Q3TextEdit::ActionWordBackspace
250 			    <<
251 	QString(" we don't succeed, we run the risk of failure. ...George W. Bush, Jr.");
252 
253     QTest::newRow( "Bush3" ) <<
254 	QString("Welcome to Mrs. Bush, and my fellow astronauts. ...Governor George W. Bush, Jr.")
255 			    << 0
256 			    << 35
257 			    << Q3TextEdit::ActionWordDelete
258 			    <<
259 	QString("Welcome to Mrs. Bush, and my fellowastronauts. ...Governor George W. Bush, Jr.");
260 
261     QTest::newRow( "Bush4" ) <<
262 	QString("Mars is essentially in the same orbit... Mars is somewhat the same distance from "
263 	"the Sun, which is very important. We have seen pictures where there are canals, we "
264 	"believe, and water. If there is water, that means there is oxygen. If oxygen, "
265 	"that means we can breathe. ...Gov GW Bush, Jr., 8/11/94")
266 			    << 0
267 			    << 57
268 			    << Q3TextEdit::ActionWordBackspace
269 			    <<
270 	QString("Mars is essentially in the same orbit... Mars is  the same distance from "
271 	"the Sun, which is very important. We have seen pictures where there are canals, we "
272 	"believe, and water. If there is water, that means there is oxygen. If oxygen, "
273 	"that means we can breathe. ...Gov GW Bush, Jr., 8/11/94");
274 
275 
276     QTest::newRow( "Bush5" ) <<
277 	QString("The Holocaust was an obscene period in our nation's history. I mean in this century's history. But we all lived in this century. I didn't live in this century.   GW Bus, 9/15/95")
278 			    << 0
279 			    << 139
280 			    << Q3TextEdit::ActionWordDelete
281 			    <<
282 	QString("The Holocaust was an obscene period in our nation's history. I mean in this century's history. But we all lived in this century. I didn't lin this century.   GW Bus, 9/15/95");
283 
284     QTest::newRow( "Bush6" ) <<
285 	QString("I believe we are on an irreversible trend toward more freedom and democracy, but that could change. GWB 5/22/98")
286 			    << 0
287 			    << 51
288 			    << Q3TextEdit::ActionWordBackspace
289 			    <<
290 	QString("I believe we are on an irreversible trend toward re freedom and democracy, but that could change. GWB 5/22/98");
291 
292     QTest::newRow( "Bush7" ) <<
293 	QString("One word sums up probably the responsibility of any Governor, and that one\n\n"
294 	"word is 'to be prepared'. ...Governor George W. Bush, Jr., 12/6/93")
295 			    << 1
296 			    << 0
297 			    << Q3TextEdit::ActionWordDelete
298 			    <<
299 	QString("One word sums up probably the responsibility of any Governor, and that one\n"
300 	"word is 'to be prepared'. ...Governor George W. Bush, Jr., 12/6/93");
301 
302     QTest::newRow( "Bush8" ) <<
303 	QString("Verbosity leads to unclear, inarticulate things.\n\n"
304 	"...Governor George W. Bush, Jr., 11/30/96")
305 			    << 1
306 			    << 0
307 			    << Q3TextEdit::ActionWordBackspace
308 			    <<
309 	QString("Verbosity leads to unclear, inarticulate things.\n"
310 	"...Governor George W. Bush, Jr., 11/30/96");
311 
312     QTest::newRow( "Bush9" ) <<
313 	QString("The future will be better tomorrow. ...Governor George W. Bush, Jr.")
314 			    << 0
315 			    << 29
316 			    << Q3TextEdit::ActionWordDelete
317 			    <<
318 	QString("The future will be better tomGovernor George W. Bush, Jr.");
319 
320     QTest::newRow( "Bush10" ) <<
321 	QString("The future will be better tomorrow. ...Governor George W. Bush, Jr.")
322 			     << 0
323 			     << 36
324 			     << Q3TextEdit::ActionWordBackspace
325 			     <<
326 	QString("The future will be better ...Governor George W. Bush, Jr.");
327 
328     QTest::newRow( "Bush11" ) <<
329 	QString("The future will be better tomorrow. ...Governor George W. Bush, Jr.")
330 			     << 0
331 			     << 37
332 			     << Q3TextEdit::ActionWordDelete
333 			     <<
334 	QString("The future will be better tomorrow. .Governor George W. Bush, Jr.");
335 
336     QTest::newRow( "Bush12" ) <<
337 	QString("The future will be better tomorrow. ...Governor George W. Bush, Jr.")
338 			     << 0
339 			     << 37
340 			     << Q3TextEdit::ActionWordBackspace
341 			     <<
342 	QString("The future will be better ..Governor George W. Bush, Jr.");
343 }
344 
cursorPosition_data()345 void tst_Q3TextEdit::cursorPosition_data()
346 {
347     QTest::addColumn<QString>("text");
348     QTest::addColumn<int>("paragraph");
349     QTest::addColumn<int>("index");
350     QTest::newRow( "curpos1" )
351 	<< QString("where to find the icon in the application and the\n"
352 	   "application name. Also describe to him what the new icon should\n"
353 	   "convey. John will create the icon and send you an email asking if it\n"
354 	   "fits your wildest dreams. Iterations are expected to occur.") << 2 << 8;
355 }
356 
cursorPosition()357 void tst_Q3TextEdit::cursorPosition()
358 {
359     if (!nativeClipboardWorking())
360         QSKIP("Native clipboard and cron-started unit tests do not work", SkipAll);
361 
362     QFETCH( QString, text );
363     QFETCH( int, paragraph );
364     QFETCH( int, index );
365 
366     int para, in;
367     QApplication::clipboard()->setText( text, QClipboard::Clipboard );
368 
369     textEdit->clear();
370     textEdit->paste();
371     textEdit->undo();
372     textEdit->paste();
373     textEdit->setCursorPosition( paragraph, index );
374     textEdit->moveCursor( Q3TextEdit::MoveWordForward, TRUE );
375     textEdit->removeSelectedText();
376     textEdit->getCursorPosition( &para, &in );
377     QCOMPARE( para, paragraph );
378     QCOMPARE( in, index );
379 }
380 
381 
text()382 void tst_Q3TextEdit::text()
383 {
384     QFETCH( int, format );
385     QFETCH( QString, text );
386     QFETCH( QString, expectedText );
387 
388     textEdit->clear();
389     textEdit->setTextFormat( (Qt::TextFormat) format );
390     QCOMPARE( textEdit->text(), QString("") );
391     textEdit->setText( text );
392 
393     QCOMPARE( textEdit->text(), expectedText );
394 }
395 
text_data()396 void tst_Q3TextEdit::text_data()
397 {
398     QTest::addColumn<int>("format");
399     QTest::addColumn<QString>("text");
400     QTest::addColumn<QString>("expectedText");
401 
402     QTest::newRow( "PlainText and nbsp" ) << int(Qt::PlainText)
403 				       << QString( "Hello" ) + QChar(0xa0) + "World"
404 				       << QString( "Hello" ) + QChar(0xa0) + "World";
405     QTest::newRow( "Empty PlainText" ) << int(Qt::PlainText)
406 				   << QString( "" )
407 				   << QString( "" );
408 
409     QTest::newRow( "Empty RichText" ) << int(Qt::RichText)
410 				   << QString( "" )
411 				   << QString( "" );
412 }
413 
copyPaste_data()414 void tst_Q3TextEdit::copyPaste_data()
415 {
416     QTest::addColumn<QString>("text");
417     QTest::addColumn<QString>("expectedText");
418 
419     QTest::newRow( "0" ) << QString( "Hello" ) << QString( "Hello" );
420     QTest::newRow( "1" ) << QString( "Hello<br>Hello" ) << QString( "Hello\nHello" );
421     QTest::newRow( "2" ) << QString( "<p>Hello</p><p>Hello</p>" ) << QString( "Hello\nHello" );
422     QTest::newRow( "3" ) << QString( "<img src=\"bullet\">Hello" ) << QString( "Hello" );
423     QTest::newRow( "4" ) << QString( "<code>Hello</code>" ) << QString( "Hello" );
424     QTest::newRow( "5" ) << QString( "<p><img src=\"bullet\"></img>Hello</p><p>Hello</p>" ) << QString( "Hello\nHello" );
425     QTest::newRow( "6" ) << QString( "<p><img src=\"bullet\">Hello</p><p>Hello</p>" ) << QString( "Hello\nHello" );
426 }
427 
428 // tests copying richtext and pasting as plain text
copyPaste()429 void tst_Q3TextEdit::copyPaste()
430 {
431     if (!nativeClipboardWorking())
432         QSKIP("Native clipboard and cron-started unit tests do not work", SkipAll);
433 
434     QFETCH( QString, text );
435     QFETCH( QString, expectedText );
436 
437     textEdit->clear();
438     textEdit->setTextFormat( Qt::RichText );
439 
440     textEdit->setText( text );
441     textEdit->selectAll();
442     textEdit->copy();
443 
444     QString pastedText = QApplication::clipboard()->text();
445     QEXPECT_FAIL( "6", "funny behaviour if img tag is not closed", Abort );
446     QCOMPARE( pastedText, expectedText );
447 }
448 
setReadOnly()449 void tst_Q3TextEdit::setReadOnly()
450 {
451     // Check that text() returns the right thing when
452     // in read-only mode
453 
454     textEdit->clear();
455     textEdit->setTextFormat( Qt::PlainText );
456     textEdit->setReadOnly( TRUE );
457     QCOMPARE( textEdit->text(), QString("") );
458     textEdit->setText("This is a test");
459     QCOMPARE( textEdit->text(), QString("This is a test") );
460     textEdit->clear();
461     QCOMPARE( textEdit->text(), QString("")  );
462     textEdit->append( "Foobar test" );
463     QCOMPARE( textEdit->text(), QString("Foobar test") );
464     textEdit->clear();
465     QCOMPARE( textEdit->text(), QString("")  );
466     textEdit->setText( "This is a test" );
467     QCOMPARE( textEdit->text(), QString("This is a test") );
468     textEdit->append( " foobar" );
469     QCOMPARE( textEdit->text(), QString("This is a test\n foobar") );
470 
471     // Reset read only state
472     textEdit->setReadOnly( FALSE );
473 }
474 /*
475 typedef QValueList<int> IntList;
476 Q_DECLARE_METATYPE(IntList)
477 */
find_data()478 void tst_Q3TextEdit::find_data()
479 {
480     // For the moment, this searches plain text, it should be extended to search
481     // rich text and log text
482 
483     QTest::addColumn<QString>("text");
484     QTest::addColumn<QString>("searchString");
485     QTest::addColumn<bool>("caseSensitive");
486     QTest::addColumn<bool>("wholeWord");
487     QTest::addColumn<bool>("forward");
488     QTest::addColumn<IntList>("paragraph");
489     QTest::addColumn<IntList>("index");
490 
491     {
492 	// Check for t's non case-sensitive not whole word forward
493 	QString text = "This is a test\nand this is another test";
494 	QString searchString = "t";
495 	bool caseSensitive = FALSE;
496 	bool wholeWord = FALSE;
497 	bool forward = TRUE;
498 	IntList paragraph;
499 	IntList index;
500 	paragraph << 0 << 0 << 0 << 1 << 1 << 1 << 1;
501 	index << 0 << 10 << 13 << 4 << 15 << 20 << 23;
502 	QTest::newRow( "t-noncs-nonww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
503     }
504 
505     {
506 	// Check for t's case-sensitive not whole word forward
507 	QString text = "This is a test\nand this is another test";
508 	QString searchString = "t";
509 	bool caseSensitive = TRUE;
510 	bool wholeWord = FALSE;
511 	bool forward = TRUE;
512 	IntList paragraph;
513 	IntList index;
514 	paragraph << 0 << 0 << 1 << 1 << 1 << 1;
515 	index << 10 << 13 << 4 << 15 << 20 << 23;
516 	QTest::newRow( "t-cs-nonww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
517     }
518 
519     {
520 	// Check for t's non case-sensitive whole word forward
521 	QString text = "This is a test\nand this is another test";
522 	QString searchString = "t";
523 	bool caseSensitive = FALSE;
524 	bool wholeWord = TRUE;
525 	bool forward = TRUE;
526 	IntList paragraph;
527 	IntList index;
528 	QTest::newRow( "t-noncs-ww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
529     }
530 
531     {
532 	// Check for t's non case-sensitive not whole word backward
533 	QString text = "This is a test\nand this is another test";
534 	QString searchString = "t";
535 	bool caseSensitive = FALSE;
536 	bool wholeWord = FALSE;
537 	bool forward = FALSE;
538 	IntList paragraph;
539 	IntList index;
540 	paragraph << 1 << 1 << 1 << 1 << 0 << 0 << 0;
541 	index << 23 << 20 << 15 << 4 << 13 << 10 << 0;
542 	QTest::newRow( "t-noncs-nonww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
543     }
544 
545     {
546 	// Check for t's case-sensitive not whole word backward
547 	QString text = "This is a test\nand this is another test";
548 	QString searchString = "t";
549 	bool caseSensitive = TRUE;
550 	bool wholeWord = FALSE;
551 	bool forward = FALSE;
552 	IntList paragraph;
553 	IntList index;
554 	paragraph << 1 << 1 << 1 << 1 << 0 << 0;
555 	index << 23 << 20 << 15 << 4 << 13 << 10;
556 	QTest::newRow( "t-cs-nonww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
557     }
558 
559     {
560 	// Check for t's non case-sensitive whole word backward
561 	QString text = "This is a test\nand this is another test";
562 	QString searchString = "t";
563 	bool caseSensitive = FALSE;
564 	bool wholeWord = TRUE;
565 	bool forward = FALSE;
566 	IntList paragraph;
567 	IntList index;
568 	QTest::newRow( "t-noncs-ww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
569     }
570 
571     {
572 	// Check for 'this' non case-sensitive not whole word forward
573 	QString text = "This is a test\nand this is another test";
574 	QString searchString = "this";
575 	bool caseSensitive = FALSE;
576 	bool wholeWord = FALSE;
577 	bool forward = TRUE;
578 	IntList paragraph;
579 	IntList index;
580 	paragraph << 0 << 1;
581 	index << 0 << 4;
582 	QTest::newRow( "this-noncs-nonww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
583     }
584 
585     {
586 	// Check for 'this' case-sensitive not whole word forward
587 	QString text = "This is a test\nand this is another test";
588 	QString searchString = "this";
589 	bool caseSensitive = TRUE;
590 	bool wholeWord = FALSE;
591 	bool forward = TRUE;
592 	IntList paragraph;
593 	IntList index;
594 	paragraph << 1;
595 	index << 4;
596 	QTest::newRow( "this-cs-nonww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
597     }
598 
599     {
600 	// Check for 'this' non case-sensitive whole word forward
601 	QString text = "This is a test\nand this is another test";
602 	QString searchString = "this";
603 	bool caseSensitive = FALSE;
604 	bool wholeWord = TRUE;
605 	bool forward = TRUE;
606 	IntList paragraph;
607 	IntList index;
608 	paragraph << 0 << 1;
609 	index << 0 << 4;
610 	QTest::newRow( "this-noncs-ww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
611     }
612 
613     {
614 	// Check for 'this' non case-sensitive not whole word backward
615 	QString text = "This is a test\nand this is another test";
616 	QString searchString = "this";
617 	bool caseSensitive = FALSE;
618 	bool wholeWord = FALSE;
619 	bool forward = FALSE;
620 	IntList paragraph;
621 	IntList index;
622 	paragraph << 1 << 0;
623 	index << 4 << 0;
624 	QTest::newRow( "this-noncs-nonww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
625     }
626 
627     {
628 	// Check for 'this' case-sensitive not whole word backward
629 	QString text = "This is a test\nand this is another test";
630 	QString searchString = "this";
631 	bool caseSensitive = TRUE;
632 	bool wholeWord = FALSE;
633 	bool forward = FALSE;
634 	IntList paragraph;
635 	IntList index;
636 	paragraph << 1;
637 	index << 4;
638 	QTest::newRow( "this-cs-nonww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
639     }
640 
641     {
642 	// Check for 'this' non case-sensitive whole word backward
643 	QString text = "This is a test\nand this is another test";
644 	QString searchString = "this";
645 	bool caseSensitive = FALSE;
646 	bool wholeWord = TRUE;
647 	bool forward = FALSE;
648 	IntList paragraph;
649 	IntList index;
650 	paragraph << 1 << 0;
651 	index << 4 << 0;
652 	QTest::newRow( "this-noncs-ww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
653     }
654 
655         {
656 	// Check for ('s non case-sensitive not whole word forward
657 	QString text = "This is (a te)st\nand (this is another test) with ( brackets)";
658 	QString searchString = "(";
659 	bool caseSensitive = FALSE;
660 	bool wholeWord = FALSE;
661 	bool forward = TRUE;
662 	IntList paragraph;
663 	IntList index;
664 	paragraph << 0 << 1 << 1;
665 	index << 8 << 4 << 32;
666 	QTest::newRow( "(-noncs-nonww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
667     }
668 
669     {
670 	// Check for ('s case-sensitive not whole word forward
671 	QString text = "This is (a te)st\nand (this is another test) with ( brackets)";
672 	QString searchString = "(";
673 	bool caseSensitive = TRUE;
674 	bool wholeWord = FALSE;
675 	bool forward = TRUE;
676 	IntList paragraph;
677 	IntList index;
678 	paragraph << 0 << 1 << 1;
679 	index << 8 << 4 << 32;
680 	QTest::newRow( "(-cs-nonww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
681     }
682 
683     {
684 	// Check for ('s non case-sensitive whole word forward
685 	QString text = "This is (a te)st\nand (this is another test) with ( brackets)";
686 	QString searchString = "(";
687 	bool caseSensitive = FALSE;
688 	bool wholeWord = TRUE;
689 	bool forward = TRUE;
690 	IntList paragraph;
691 	IntList index;
692 	paragraph << 1;
693 	index << 32;
694 	QTest::newRow( "(-noncs-ww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
695     }
696 
697     {
698 	// Check for ('s non case-sensitive not whole word backward
699 	QString text = "This is (a te)st\nand (this is another test) with ( brackets)";
700 	QString searchString = "(";
701 	bool caseSensitive = FALSE;
702 	bool wholeWord = FALSE;
703 	bool forward = FALSE;
704 	IntList paragraph;
705 	IntList index;
706 	paragraph << 1 << 1 << 0;
707 	index << 32 << 4 << 8;
708 	QTest::newRow( "(-noncs-nonww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
709     }
710 
711     {
712 	// Check for ('s case-sensitive not whole word backward
713 	QString text = "This is (a te)st\nand (this is another test) with ( brackets)";
714 	QString searchString = "(";
715 	bool caseSensitive = TRUE;
716 	bool wholeWord = FALSE;
717 	bool forward = FALSE;
718 	IntList paragraph;
719 	IntList index;
720 	paragraph << 1 << 1 << 0;
721 	index << 32 << 4 << 8;
722 	QTest::newRow( "(-cs-nonww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
723     }
724 
725     {
726 	// Check for ('s non case-sensitive whole word backward
727 	QString text = "This is (a te)st\nand (this is another test) with ( brackets)";
728 	QString searchString = "(";
729 	bool caseSensitive = FALSE;
730 	bool wholeWord = TRUE;
731 	bool forward = FALSE;
732 	IntList paragraph;
733 	IntList index;
734 	paragraph << 1;
735 	index << 32;
736 	QTest::newRow( "(-noncs-ww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
737     }
738 
739     {
740 	// Check for (this's non case-sensitive whole word backward
741 	QString text = "This is (a te)st\nand (this is another test) with (brackets)";
742 	QString searchString = "(this";
743 	bool caseSensitive = FALSE;
744 	bool wholeWord = TRUE;
745 	bool forward = FALSE;
746 	IntList paragraph;
747 	IntList index;
748 	paragraph << 1;
749 	index << 4;
750 	QTest::newRow( "(this-noncs-ww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
751     }
752 
753     {
754 	// Check for (this's non case-sensitive whole word forward
755 	QString text = "This is (a te)st\nand (this is another test) with (brackets)";
756 	QString searchString = "(this";
757 	bool caseSensitive = FALSE;
758 	bool wholeWord = TRUE;
759 	bool forward = TRUE;
760 	IntList paragraph;
761 	IntList index;
762 	paragraph << 1;
763 	index << 4;
764 	QTest::newRow( "(this-noncs-ww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
765     }
766 
767     {
768 	// Check for " "'s non case-sensitive non whole word forward
769 	QString text = "foo";
770 	QString searchString = " ";
771 	bool caseSensitive = false;
772 	bool wholeWord = false;
773 	bool forward = true;
774 	IntList paragraph;
775 	IntList index;
776 // 	paragraph << 0 << 1 << 1 << 1;
777 //         index << 3 << 0 << 6 << 12;
778 	QTest::newRow( " -noncs-nonww-forward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
779     }
780 
781     {
782 	// Check for " "'s non case-sensitive non whole word backward
783 	QString text = "foo ";
784 	QString searchString = " ";
785 	bool caseSensitive = false;
786 	bool wholeWord = false;
787 	bool forward = false;
788 	IntList paragraph;
789 	IntList index;
790 	paragraph << 0;
791         index << 3;
792 	QTest::newRow( " -noncs-nonww-backward" ) << text << searchString << caseSensitive << wholeWord << forward << paragraph << index;
793     }
794 }
795 
796 
find()797 void tst_Q3TextEdit::find()
798 {
799     QFETCH( QString, text );
800     QFETCH( QString, searchString );
801     QFETCH( bool, caseSensitive );
802     QFETCH( bool, wholeWord );
803     QFETCH( bool, forward );
804     QFETCH( IntList, paragraph );
805     QFETCH( IntList, index );
806 
807     textEdit->clear();
808     textEdit->setTextFormat( Qt::PlainText );
809     textEdit->setText( text );
810 
811     IntList::Iterator pIt;
812     IntList::Iterator iIt = index.begin();
813     int paraFound = forward ? 0 : INT_MAX;
814     int indexFound = forward ? 0 : INT_MAX;
815 
816     QEXPECT_FAIL(" -noncs-nonww-forward", "Searching for space is broken in Q3TextEdit because of the extra space added at the end of all paragraphs", Abort );
817     QEXPECT_FAIL(" -noncs-nonww-backward", "Searching for space is broken in Q3TextEdit because of the extra space added at the end of all paragraphs", Abort );
818 
819     // It should not find anything
820     if ( !paragraph.count() ) {
821 	QVERIFY( !textEdit->find( searchString, caseSensitive, wholeWord, forward, &paraFound, &indexFound ) );
822     } else {
823 	for ( pIt = paragraph.begin(); pIt != paragraph.end(); ++pIt ) {
824 	    QVERIFY( textEdit->find( searchString, caseSensitive, wholeWord, forward, &paraFound, &indexFound ) );
825 	    QCOMPARE( paraFound, (*pIt) );
826 	    QCOMPARE( indexFound, (*iIt) );
827 
828 	    // This sounds dubious to me, it should search from the next character specified by indexFound
829 	    if ( forward )
830 		indexFound++;
831 	    else
832 		indexFound--;
833 
834 	    ++iIt;
835 	}
836     }
837 }
838 
findSC()839 void tst_Q3TextEdit::findSC()
840 {
841     // Special bug case #29649 test
842     textEdit->clear();
843     textEdit->setTextFormat(Qt::PlainText);
844     textEdit->setText("foo do soo boo arg\ndf df foo a;ls lkdf lsdkjf");
845     textEdit->setCursorPosition(1, 16);
846     int paraFound, indexFound;
847     QVERIFY(textEdit->find("foo", FALSE, FALSE, FALSE));
848     textEdit->getCursorPosition(&paraFound, &indexFound);
849     QCOMPARE(paraFound, 1);
850     QCOMPARE(indexFound, 6);
851     QVERIFY(textEdit->find("foo", FALSE, FALSE, FALSE));
852     textEdit->getCursorPosition(&paraFound, &indexFound);
853     QCOMPARE(paraFound, 0);
854     QCOMPARE(indexFound, 0);
855     QVERIFY(!textEdit->find("foo", FALSE, FALSE, FALSE));
856     QVERIFY(textEdit->find("foo", FALSE, FALSE, FALSE));
857     textEdit->getCursorPosition(&paraFound, &indexFound);
858     QCOMPARE(paraFound, 1);
859     QCOMPARE(indexFound, 6);
860 }
861 
862 
863 
findBackwards()864 void tst_Q3TextEdit::findBackwards()
865 {
866     textEdit->clear();
867     textEdit->setTextFormat(Qt::PlainText);
868     textEdit->setText("ABCABCABCABC");
869     textEdit->setCursorPosition(0, 3);
870     QVERIFY(textEdit->find("ABC", FALSE, FALSE, FALSE));
871     QCOMPARE(textEdit->selectedText(), QString("ABC"));
872     int pFrom, pTo, iFrom, iTo;
873     QString qw;
874 
875     textEdit->getSelection(&pFrom, &iFrom, &pTo, &iTo);
876     QCOMPARE(pFrom, 0);
877     QCOMPARE(iFrom, 0);
878     QCOMPARE(pTo, 0);
879     QCOMPARE(iTo, 3);
880 }
redoAvailableEmitted(bool t)881 void tst_Q3TextEdit::redoAvailableEmitted( bool t )
882 {
883     redoA = t;
884 }
885 
undoAvailableEmitted(bool t)886 void tst_Q3TextEdit::undoAvailableEmitted( bool t )
887 {
888     undoA = t;
889 }
890 
copyAvailableEmitted(bool t)891 void tst_Q3TextEdit::copyAvailableEmitted( bool t )
892 {
893     copyA = t;
894 }
895 
cut()896 void tst_Q3TextEdit::cut()
897 {
898     connect( textEdit, SIGNAL( copyAvailable(bool) ), this, SLOT( copyAvailableEmitted(bool) ) );
899     copyA = FALSE;
900     textEdit->setText( "I believe that people who are going to commit crimes shouldn't have guns" );
901     textEdit->selectAll();
902     QTest::qWait( 2000 );
903     QVERIFY( copyA );
904     textEdit->cut();
905     QTest::qWait( 2000 );
906     QVERIFY( !copyA );
907 }
908 
clear()909 void tst_Q3TextEdit::clear()
910 {
911     // Clear is actually tested all over the place, this is
912     // really just to test for task 21355
913     textEdit->clear();
914     textEdit->setTextFormat( Qt::RichText );
915     textEdit->setText( "<table align=right></table>" );
916     textEdit->clear();
917     // If it got here, then it didn't crash
918     QVERIFY( TRUE );
919 }
920 
insert()921 void tst_Q3TextEdit::insert()
922 {
923     Qt::TextFormat fmt = textEdit->textFormat();
924     textEdit->setTextFormat(Qt::LogText);
925     textEdit->setText("<blue>The<red> following: </red><b>fooooooooooooooooooff</b>\nLine <green>Number 2\nLine</green> Number 3");
926     textEdit->insertParagraph("<orange>#orange#</orange>", 1);
927     textEdit->insertAt(" #\nper\nka<blue>ar<yellow>e\nreo</yellow>le</blue># \n", 2, 3 );
928     textEdit->insertAt("\n#<b>o</b><i>l</i><u>e</u>#\n\n", 100, 100);
929     textEdit->insertAt("<u>#o\nle#</u>", 0, 10);
930     QString result = "<blue>The<red> follow<u>#o\nle#</u>ing: </red><b>fooooooooooooooooooff</b>\n<orange>#orange#</orange>\n"
931 		     "Lin #\nper\nka<blue>ar<yellow>e\nreo</yellow>le</blue># \ne <green>Number 2\nLine</green> Number 3\n"
932 		     "#<b>o</b><i>l</i><u>e</u>#\n\n\n";
933     QCOMPARE(textEdit->text(), result);
934     textEdit->setTextFormat(fmt);
935 }
936 
keyClicks_data()937 void tst_Q3TextEdit::keyClicks_data()
938 {
939     QTest::addColumn<QString>("inputString");
940 
941     QTest::newRow("English") << "This is not a sentence.";
942     QTest::newRow("Norwegian") << "\x0e6\x0f8\x0e5\x0c6\x0d8\x0c5 er norske bokstaver.";
943 }
944 
keyClicks()945 void tst_Q3TextEdit::keyClicks()
946 {
947     QFETCH(QString, inputString);
948 
949     textEdit->clear();
950     textEdit->setTextFormat(Qt::PlainText);
951     textEdit->setReadOnly(false);
952 
953     QVERIFY(textEdit->text().isEmpty());
954     QTest::keyClicks(textEdit, inputString);
955     QCOMPARE(textEdit->text(), inputString);
956 }
957 
958 
959 
selectAll()960 void tst_Q3TextEdit::selectAll()
961 {
962     QString testString = "This is test for task #24092";
963     textEdit->setText( testString );
964 
965     textEdit->setTextFormat(Qt::PlainText);
966     textEdit->selectAll(TRUE);
967     QVERIFY( textEdit->hasSelectedText() );
968     textEdit->selectAll(FALSE);
969     QVERIFY( !textEdit->hasSelectedText() );
970 
971     textEdit->setTextFormat(Qt::RichText);
972     textEdit->selectAll(TRUE);
973     QVERIFY( textEdit->hasSelectedText() );
974     textEdit->selectAll(FALSE);
975     QVERIFY( !textEdit->hasSelectedText() );
976     textEdit->setTextFormat(Qt::LogText);
977     textEdit->selectAll(TRUE);
978     QVERIFY( textEdit->hasSelectedText() );
979     textEdit->selectAll(FALSE);
980     QVERIFY( !textEdit->hasSelectedText() );
981 }
982 
setCurrentFont()983 void tst_Q3TextEdit::setCurrentFont()
984 {
985     textEdit->clear();
986     textEdit->setTextFormat(Qt::LogText);
987     textEdit->setCurrentFont(QFont("Courier New", 9));
988     textEdit->setText("Just some dummy text");
989     QCOMPARE(textEdit->text(), QString("Just some dummy text\n"));
990 }
991 
undoRedo()992 void tst_Q3TextEdit::undoRedo()
993 {
994     Q3TextEdit edit;
995     edit.setTextFormat(Qt::PlainText);
996 
997     QString deftext("Just some text");
998     edit.setText(deftext);
999     edit.insertAt("<tag>",0, 5);
1000     QCOMPARE(edit.text(), QString("Just <tag>some text"));
1001     edit.undo();
1002     QCOMPARE(edit.text(), deftext);
1003     edit.insertAt("<tag>",0, 5);
1004     edit.insertAt("</tag>",0, 14);
1005     QCOMPARE(edit.text(), QString("Just <tag>some</tag> text"));
1006     edit.undo();
1007     QCOMPARE(edit.text(), QString("Just <tag>some text"));
1008     edit.undo();
1009     QCOMPARE(edit.text(), QString("Just some text"));
1010     edit.insertAt("<tag>",0, 5);
1011     edit.insertAt("</tag>",0, 10);
1012     QCOMPARE(edit.text(), QString("Just <tag></tag>some text"));
1013     edit.undo();
1014     QCOMPARE(edit.text(), QString("Just some text"));
1015 }
1016 
length_data()1017 void tst_Q3TextEdit::length_data()
1018 {
1019     // The expected length values are based on what is returned in Qt 3.2.1.
1020     // We don't want the semantics of this function to change again, no
1021     // matter how broken it is, so if this function fails, the test data has to be seen as
1022     // correct.  In Qt 4.0, this function will not exist in this form.
1023 
1024     QTest::addColumn<int>("textFormat");
1025     QTest::addColumn<QString>("text");
1026     QTest::addColumn<int>("expectedLength");
1027 
1028     QTest::newRow("plainText") << int(Qt::PlainText) << "This is a test" << 14;
1029     QTest::newRow("plainTextNewLines") << int(Qt::PlainText) << "This is a test\nThis is a test\nThis is a test" << 44;
1030     QTest::newRow("logText") << int(Qt::LogText) << "This is a test" << 14;
1031     QTest::newRow("logTextNewLines") << int(Qt::LogText) << "This is a test\nThis is a test\nThis is a test" << 42;
1032     QTest::newRow("logTextTags") << int(Qt::LogText) << "<b>This is a test</b>" << 14;
1033     QTest::newRow("logTextTagsNewLines") << int(Qt::LogText) << "<b>This is a test\nThis is a test\nThis is a test</b>" << 42;
1034     QTest::newRow("richText") << int(Qt::RichText) << "This is a test" << 14;
1035     QTest::newRow("richTextNewLines") << int(Qt::RichText) << "This is a test\nThis is a test\nThis is a test" << 44;
1036     QTest::newRow("richTextTags") << int(Qt::RichText) << "<b>This is a test</b>" << 14;
1037 }
1038 
length()1039 void tst_Q3TextEdit::length()
1040 {
1041     QFETCH(int, textFormat);
1042     QFETCH(QString, text);
1043     QFETCH(int, expectedLength);
1044 
1045     textEdit->setTextFormat((Qt::TextFormat)textFormat);
1046     textEdit->setText(text);
1047     QCOMPARE(textEdit->length(), expectedLength);
1048 }
1049 
getSelection_data()1050 void tst_Q3TextEdit::getSelection_data()
1051 {
1052     QTest::addColumn<int>("textFormat");
1053     QTest::addColumn<QString>("text");
1054 
1055     QTest::addColumn<int>("paragFrom");
1056     QTest::addColumn<int>("indexFrom");
1057     QTest::addColumn<int>("paragTo");
1058     QTest::addColumn<int>("indexTo");
1059 
1060     QTest::addColumn<int>("selParagFrom");
1061     QTest::addColumn<int>("selIndexFrom");
1062     QTest::addColumn<int>("selParagTo");
1063     QTest::addColumn<int>("selIndexTo");
1064 
1065     QTest::newRow("plainText") << int(Qt::PlainText) << "This is a test" << 0 << 0 << 0 << 2 << 0 << 0 << 0 << 2;
1066     QTest::newRow("richText") << int(Qt::RichText) << "This is a test" << 0 << 0 << 0 << 2 << 0 << 0 << 0 << 2;
1067     QTest::newRow("logText") << int(Qt::LogText) << "This is a test" << 0 << 0 << 0 << 2 << 0 << 0 << 0 << 2;
1068 }
1069 
getSelection()1070 void tst_Q3TextEdit::getSelection()
1071 {
1072     QFETCH(int, textFormat);
1073     QFETCH(QString, text);
1074 
1075     QFETCH(int, paragFrom);
1076     QFETCH(int, indexFrom);
1077     QFETCH(int, paragTo);
1078     QFETCH(int, indexTo);
1079 
1080     QFETCH(int, selParagFrom);
1081     QFETCH(int, selIndexFrom);
1082     QFETCH(int, selParagTo);
1083     QFETCH(int, selIndexTo);
1084 
1085     int pFr, iFr, pTo, iTo;
1086     textEdit->setText(text);
1087     textEdit->setTextFormat((Qt::TextFormat)textFormat);
1088     textEdit->setSelection(paragFrom, indexFrom, paragTo, indexTo);
1089     textEdit->getSelection(&pFr, &iFr, &pTo, &iTo);
1090 
1091     QCOMPARE(pFr, selParagFrom);
1092     QCOMPARE(iFr, selIndexFrom);
1093     QCOMPARE(pTo, selParagTo);
1094     QCOMPARE(iTo, selIndexTo);
1095 }
1096 
anchorTest()1097 void tst_Q3TextEdit::anchorTest()
1098 {
1099     // This is from task 57709
1100     Q3TextEdit edit;
1101     QString richText = "<p dir=\"ltr\"><a name=\"Gold\"></a>something</p>\n"
1102                        "<p dir=\"ltr\"><a name=\"Silver\"></a>more"
1103                        "<a name=\"Bronze\"></a>stuff</p>\n";
1104     edit.setText(richText);
1105 
1106     QString expected = "<html><head><meta name=\"qrichtext\" content=\"1\" /></head>"
1107                     "<body style=\"font-size:%1pt;font-family:%2\">\n"
1108                        + richText + "</body></html>\n";
1109     QFont f = edit.font();
1110     expected = expected.arg(f.pointSize()).arg(f.family());
1111     QCOMPARE(edit.text(),expected);
1112 }
1113 
1114 QTEST_MAIN(tst_Q3TextEdit)
1115 #include "tst_q3textedit.moc"
1116 
1117