]> git.saurik.com Git - wxWidgets.git/blame - tests/controls/textctrltest.cpp
Fixed capitalisation
[wxWidgets.git] / tests / controls / textctrltest.cpp
CommitLineData
c0d9b217 1///////////////////////////////////////////////////////////////////////////////
f0f6a32d 2// Name: tests/controls/textctrltest.cpp
c0d9b217
VZ
3// Purpose: wxTextCtrl unit test
4// Author: Vadim Zeitlin
5// Created: 2007-09-25
c0d9b217
VZ
6// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwidgets.org>
7///////////////////////////////////////////////////////////////////////////////
8
9// ----------------------------------------------------------------------------
10// headers
11// ----------------------------------------------------------------------------
12
13#include "testprec.h"
14
232fdc63
VZ
15#if wxUSE_TEXTCTRL
16
c0d9b217
VZ
17#ifdef __BORLANDC__
18 #pragma hdrstop
19#endif
20
21#ifndef WX_PRECOMP
22 #include "wx/app.h"
23 #include "wx/textctrl.h"
24#endif // WX_PRECOMP
25
8859c729
VZ
26#include "wx/scopeguard.h"
27
f0f6a32d 28#include "textentrytest.h"
232fdc63
VZ
29#include "testableframe.h"
30#include "asserthelper.h"
31#include "wx/uiaction.h"
f0f6a32d 32
358fb6ad
VZ
33static const int TEXT_HEIGHT = 200;
34
c0d9b217
VZ
35// ----------------------------------------------------------------------------
36// test class
37// ----------------------------------------------------------------------------
38
232fdc63 39class TextCtrlTestCase : public TextEntryTestCase, public CppUnit::TestCase
c0d9b217
VZ
40{
41public:
42 TextCtrlTestCase() { }
43
44 virtual void setUp();
45 virtual void tearDown();
46
47private:
f0f6a32d
VZ
48 virtual wxTextEntry *GetTestEntry() const { return m_text; }
49 virtual wxWindow *GetTestWindow() const { return m_text; }
50
d9abe7f2
VZ
51 #define SINGLE_AND_MULTI_TESTS() \
52 WXUISIM_TEST( ReadOnly ); \
53 CPPUNIT_TEST( StreamInput ); \
54 CPPUNIT_TEST( Redirector )
55
c0d9b217 56 CPPUNIT_TEST_SUITE( TextCtrlTestCase );
d9abe7f2 57 // These tests run for single line text controls.
f0f6a32d 58 wxTEXT_ENTRY_TESTS();
232fdc63 59 WXUISIM_TEST( MaxLength );
d9abe7f2
VZ
60 SINGLE_AND_MULTI_TESTS();
61
62 // Now switch to the multi-line text controls.
358fb6ad 63 CPPUNIT_TEST( PseudoTestSwitchToMultiLineStyle );
d9abe7f2
VZ
64
65 // Rerun some of the tests above. Notice that not all of them pass, so
66 // we can't just use wxTEXT_ENTRY_TESTS() here. For some of them it's
67 // normal, e.g. Hint() test isn't supposed to work for multi-line
68 // controls. Others, such as InsertionPoint() and TextChangeEvents()
69 // don't pass neither but this could be a bug.
70 CPPUNIT_TEST( SetValue );
71 CPPUNIT_TEST( Selection );
72 CPPUNIT_TEST( Replace );
73 WXUISIM_TEST( Editable );
74 CPPUNIT_TEST( CopyPaste );
75 CPPUNIT_TEST( UndoRedo );
76
77 SINGLE_AND_MULTI_TESTS();
78
79
80 // All tests from now on are for multi-line controls only.
358fb6ad 81 CPPUNIT_TEST( MultiLineReplace );
232fdc63
VZ
82 //WXUISIM_TEST( ProcessEnter );
83 WXUISIM_TEST( Url );
84 CPPUNIT_TEST( Style );
be74a2a2 85 CPPUNIT_TEST( FontStyle );
232fdc63
VZ
86 CPPUNIT_TEST( Lines );
87 CPPUNIT_TEST( LogTextCtrl );
6ce83213
VZ
88 CPPUNIT_TEST( PositionToCoords );
89 CPPUNIT_TEST( PositionToCoordsRich );
90 CPPUNIT_TEST( PositionToCoordsRich2 );
c0d9b217
VZ
91 CPPUNIT_TEST_SUITE_END();
92
358fb6ad
VZ
93 void PseudoTestSwitchToMultiLineStyle()
94 {
95 ms_style = wxTE_MULTILINE;
96 }
97
d911dc04 98 void MultiLineReplace();
232fdc63
VZ
99 void ReadOnly();
100 void MaxLength();
101 void StreamInput();
102 void Redirector();
103 //void ProcessEnter();
104 void Url();
105 void Style();
be74a2a2 106 void FontStyle();
232fdc63
VZ
107 void Lines();
108 void LogTextCtrl();
6ce83213
VZ
109 void PositionToCoords();
110 void PositionToCoordsRich();
111 void PositionToCoordsRich2();
112
113 void DoPositionToCoordsTestWithStyle(long style);
d911dc04 114
358fb6ad
VZ
115 // Create the control with the following styles added to ms_style which may
116 // (or not) already contain wxTE_MULTILINE.
117 void CreateText(long extraStyles);
118
c0d9b217 119 wxTextCtrl *m_text;
c0d9b217 120
358fb6ad
VZ
121 static long ms_style;
122
c0d9b217
VZ
123 DECLARE_NO_COPY_CLASS(TextCtrlTestCase)
124};
125
126// register in the unnamed registry so that these tests are run by default
127CPPUNIT_TEST_SUITE_REGISTRATION( TextCtrlTestCase );
128
e3778b4d 129// also include in its own registry so that these tests can be run alone
c0d9b217
VZ
130CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TextCtrlTestCase, "TextCtrlTestCase" );
131
132// ----------------------------------------------------------------------------
133// test initialization
134// ----------------------------------------------------------------------------
135
358fb6ad
VZ
136// This is 0 initially and set to wxTE_MULTILINE later to allow running the
137// same tests for both single and multi line controls.
138long TextCtrlTestCase::ms_style = 0;
139
140void TextCtrlTestCase::CreateText(long extraStyles)
141{
142 wxSize size;
143 if ( ms_style == wxTE_MULTILINE )
144 size = wxSize(400, TEXT_HEIGHT);
145
146 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
147 wxDefaultPosition, size,
148 ms_style | extraStyles);
149}
150
c0d9b217
VZ
151void TextCtrlTestCase::setUp()
152{
358fb6ad 153 CreateText(ms_style);
c0d9b217
VZ
154}
155
156void TextCtrlTestCase::tearDown()
157{
232fdc63 158 wxDELETE(m_text);
c0d9b217
VZ
159}
160
161// ----------------------------------------------------------------------------
162// tests themselves
163// ----------------------------------------------------------------------------
164
d911dc04
VZ
165void TextCtrlTestCase::MultiLineReplace()
166{
d911dc04
VZ
167 m_text->SetValue("Hello replace\n"
168 "0123456789012");
169 m_text->SetInsertionPoint(0);
170
171 m_text->Replace(6, 13, "changed");
172
173 CPPUNIT_ASSERT_EQUAL("Hello changed\n"
174 "0123456789012",
175 m_text->GetValue());
176 CPPUNIT_ASSERT_EQUAL(13, m_text->GetInsertionPoint());
177
178 m_text->Replace(13, -1, "");
179 CPPUNIT_ASSERT_EQUAL("Hello changed", m_text->GetValue());
180 CPPUNIT_ASSERT_EQUAL(13, m_text->GetInsertionPoint());
232fdc63
VZ
181}
182
183void TextCtrlTestCase::ReadOnly()
184{
185#if wxUSE_UIACTIONSIMULATOR
186 // we need a read only control for this test so recreate it
187 delete m_text;
358fb6ad 188 CreateText(wxTE_READONLY);
232fdc63 189
ce7fe42e 190 EventCounter updated(m_text, wxEVT_TEXT);
232fdc63
VZ
191
192 m_text->SetFocus();
193
194 wxUIActionSimulator sim;
195 sim.Text("abcdef");
196 wxYield();
197
198 CPPUNIT_ASSERT_EQUAL("", m_text->GetValue());
744d91d4 199 CPPUNIT_ASSERT_EQUAL(0, updated.GetCount());
232fdc63
VZ
200
201 // SetEditable() is supposed to override wxTE_READONLY
202 m_text->SetEditable(true);
64fd19db
SC
203
204#ifdef __WXOSX__
205 // a ready only text field might not have been focusable at all
206 m_text->SetFocus();
207#endif
232fdc63
VZ
208
209 sim.Text("abcdef");
210 wxYield();
211
212 CPPUNIT_ASSERT_EQUAL("abcdef", m_text->GetValue());
744d91d4 213 CPPUNIT_ASSERT_EQUAL(6, updated.GetCount());
232fdc63
VZ
214#endif
215}
216
217void TextCtrlTestCase::MaxLength()
218{
219#if wxUSE_UIACTIONSIMULATOR
ce7fe42e
VZ
220 EventCounter updated(m_text, wxEVT_TEXT);
221 EventCounter maxlen(m_text, wxEVT_TEXT_MAXLEN);
232fdc63
VZ
222
223 m_text->SetFocus();
224 m_text->SetMaxLength(10);
225
226 wxUIActionSimulator sim;
227 sim.Text("abcdef");
228 wxYield();
229
744d91d4 230 CPPUNIT_ASSERT_EQUAL(0, maxlen.GetCount());
232fdc63
VZ
231
232 sim.Text("ghij");
233 wxYield();
234
744d91d4
SL
235 CPPUNIT_ASSERT_EQUAL(0, maxlen.GetCount());
236 CPPUNIT_ASSERT_EQUAL(10, updated.GetCount());
237
238 maxlen.Clear();
239 updated.Clear();
232fdc63
VZ
240
241 sim.Text("k");
242 wxYield();
243
744d91d4
SL
244 CPPUNIT_ASSERT_EQUAL(1, maxlen.GetCount());
245 CPPUNIT_ASSERT_EQUAL(0, updated.GetCount());
246
247 maxlen.Clear();
248 updated.Clear();
232fdc63
VZ
249
250 m_text->SetMaxLength(0);
251
252 sim.Text("k");
253 wxYield();
254
744d91d4
SL
255 CPPUNIT_ASSERT_EQUAL(0, maxlen.GetCount());
256 CPPUNIT_ASSERT_EQUAL(1, updated.GetCount());
232fdc63
VZ
257#endif
258}
259
260void TextCtrlTestCase::StreamInput()
261{
262#ifndef __WXOSX__
8859c729
VZ
263 {
264 // Ensure we use decimal point and not a comma.
265 char * const locOld = setlocale(LC_NUMERIC, "C");
266 wxON_BLOCK_EXIT2( setlocale, (int)LC_NUMERIC, locOld );
267
268 *m_text << "stringinput"
269 << 10
270 << 1000L
271 << 3.14f
272 << 2.71
273 << 'a'
274 << L'b';
275 }
232fdc63
VZ
276
277 CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71ab", m_text->GetValue());
278
279 m_text->SetValue("");
280
281#if wxHAS_TEXT_WINDOW_STREAM
282
283 std::ostream stream(m_text);
284
285 // We don't test a wide character as this is not a wide stream
286 stream << "stringinput"
287 << 10
288 << 1000L
289 << 3.14f
290 << 2.71
291 << 'a';
292
293 stream.flush();
294
295 CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71a", m_text->GetValue());
296
8859c729
VZ
297#endif // wxHAS_TEXT_WINDOW_STREAM
298#endif // !__WXOSX__
232fdc63
VZ
299}
300
301void TextCtrlTestCase::Redirector()
302{
303#if wxHAS_TEXT_WINDOW_STREAM && wxUSE_STD_IOSTREAM
304
305 wxStreamToTextRedirector redirect(m_text);
306
307 std::cout << "stringinput"
308 << 10
309 << 1000L
310 << 3.14f
311 << 2.71
312 << 'a';
313
314 CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71a", m_text->GetValue());
315
316#endif
317}
318
319#if 0
320void TextCtrlTestCase::ProcessEnter()
321{
322#if wxUSE_UIACTIONSIMULATOR
323 wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(),
324 wxTestableFrame);
325
ce7fe42e 326 EventCounter count(m_text, wxEVT_TEXT_ENTER);
232fdc63
VZ
327
328 m_text->SetFocus();
329
330 wxUIActionSimulator sim;
331 sim.Char(WXK_RETURN);
332 wxYield();
333
ce7fe42e 334 CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_TEXT_ENTER));
232fdc63
VZ
335
336 // we need a text control with wxTE_PROCESS_ENTER for this test
337 delete m_text;
358fb6ad 338 CreateText(wxTE_PROCESS_ENTER);
232fdc63
VZ
339
340 m_text->SetFocus();
341
342 sim.Char(WXK_RETURN);
343 wxYield();
344
ce7fe42e 345 CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount(wxEVT_TEXT_ENTER));
232fdc63
VZ
346#endif
347}
348#endif
349
350void TextCtrlTestCase::Url()
351{
352#if wxUSE_UIACTIONSIMULATOR && defined(__WXMSW__)
353 delete m_text;
358fb6ad 354 CreateText(wxTE_RICH | wxTE_AUTO_URL);
232fdc63 355
ce7fe42e 356 EventCounter url(m_text, wxEVT_TEXT_URL);
232fdc63
VZ
357
358 m_text->AppendText("http://www.wxwidgets.org");
359
360 wxUIActionSimulator sim;
361 sim.MouseMove(m_text->ClientToScreen(wxPoint(5, 5)));
362 sim.MouseClick();
363 wxYield();
364
744d91d4 365 CPPUNIT_ASSERT_EQUAL(1, url.GetCount());
232fdc63
VZ
366#endif
367}
368
369void TextCtrlTestCase::Style()
370{
371#ifndef __WXOSX__
372 delete m_text;
373 // We need wxTE_RICH under windows for style support
358fb6ad 374 CreateText(wxTE_RICH);
232fdc63
VZ
375
376 // Red text on a white background
377 m_text->SetDefaultStyle(wxTextAttr(*wxRED, *wxWHITE));
378
379 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxRED);
380 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(),
381 *wxWHITE);
382
383 m_text->AppendText("red on white ");
384
385 // Red text on a grey background
386 m_text->SetDefaultStyle(wxTextAttr(wxNullColour, *wxLIGHT_GREY));
387
388 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxRED);
389 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(),
390 *wxLIGHT_GREY);
391
392 m_text->AppendText("red on grey ");
393
394 // Blue text on a grey background
395 m_text->SetDefaultStyle(wxTextAttr(*wxBLUE));
396
397
398 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxBLUE);
399 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(),
400 *wxLIGHT_GREY);
401
402 m_text->AppendText("blue on grey");
403
404 // Get getting the style at a specific location
405 wxTextAttr style;
406
407 // We have to check that styles are supported
408 if(m_text->GetStyle(3, style))
409 {
410 CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED);
411 CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE);
412 }
413
414 // And then setting the style
415 if(m_text->SetStyle(15, 18, style))
416 {
417 m_text->GetStyle(17, style);
418
419 CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED);
420 CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE);
421 }
422#endif
423}
424
be74a2a2
VZ
425void TextCtrlTestCase::FontStyle()
426{
427 // We need wxTE_RICH under MSW and wxTE_MULTILINE under GTK for style
428 // support so recreate the control with these styles.
429 delete m_text;
358fb6ad 430 CreateText(wxTE_RICH);
be74a2a2
VZ
431
432 // Check that we get back the same font from GetStyle() after setting it
433 // with SetDefaultStyle().
434 wxFont fontIn(14,
435 wxFONTFAMILY_DEFAULT,
436 wxFONTSTYLE_NORMAL,
437 wxFONTWEIGHT_NORMAL);
438 wxTextAttr attrIn;
439 attrIn.SetFont(fontIn);
440 if ( !m_text->SetDefaultStyle(attrIn) )
441 {
442 // Skip the test if the styles are not supported.
443 return;
444 }
445
446 m_text->AppendText("Default font size 14");
447
448 wxTextAttr attrOut;
449 m_text->GetStyle(5, attrOut);
450
451 CPPUNIT_ASSERT( attrOut.HasFont() );
452
453 wxFont fontOut = attrOut.GetFont();
454#ifdef __WXMSW__
455 // Under MSW we get back an encoding in the font even though we hadn't
456 // specified it originally. It's not really a problem but we need this hack
457 // to prevent the assert below from failing because of it.
458 fontOut.SetEncoding(fontIn.GetEncoding());
459#endif
460 CPPUNIT_ASSERT_EQUAL( fontIn, fontOut );
461
462
463 // Also check the same for SetStyle().
464 fontIn.SetPointSize(10);
465 fontIn.SetWeight(wxFONTWEIGHT_BOLD);
466 attrIn.SetFont(fontIn);
467 m_text->SetStyle(0, 6, attrIn);
468
469 m_text->GetStyle(4, attrOut);
470 CPPUNIT_ASSERT( attrOut.HasFont() );
471
472 fontOut = attrOut.GetFont();
473#ifdef __WXMSW__
474 fontOut.SetEncoding(fontIn.GetEncoding());
475#endif
476 CPPUNIT_ASSERT_EQUAL( fontIn, fontOut );
477}
478
232fdc63
VZ
479void TextCtrlTestCase::Lines()
480{
232fdc63
VZ
481 m_text->SetValue("line1\nline2\nlong long line 3");
482 m_text->Refresh();
483 m_text->Update();
484
485 CPPUNIT_ASSERT_EQUAL(3, m_text->GetNumberOfLines());
486 CPPUNIT_ASSERT_EQUAL(5, m_text->GetLineLength(0));
487 CPPUNIT_ASSERT_EQUAL("line2", m_text->GetLineText(1));
488 CPPUNIT_ASSERT_EQUAL(16, m_text->GetLineLength(2));
489
490 m_text->AppendText("\n\nMore text on line 5");
491
492 CPPUNIT_ASSERT_EQUAL(5, m_text->GetNumberOfLines());
493 CPPUNIT_ASSERT_EQUAL(0, m_text->GetLineLength(3));
494 CPPUNIT_ASSERT_EQUAL("", m_text->GetLineText(3));
567e5e47
VZ
495
496 // Verify that wrapped lines count as 2 lines.
497 //
498 // This currently doesn't work neither in wxGTK nor wxOSX/Cocoa, see
499 // #12366, where GetNumberOfLines() always returns the number of logical,
500 // not physical, lines.
501 m_text->AppendText("\n" + wxString(50, '1') + ' ' + wxString(50, '2'));
502#if defined(__WXGTK__) || defined(__WXOSX_COCOA__)
503 CPPUNIT_ASSERT_EQUAL(6, m_text->GetNumberOfLines());
504#else
505 CPPUNIT_ASSERT_EQUAL(7, m_text->GetNumberOfLines());
232fdc63
VZ
506#endif
507}
508
509void TextCtrlTestCase::LogTextCtrl()
510{
232fdc63
VZ
511 CPPUNIT_ASSERT(m_text->IsEmpty());
512
513 wxLogTextCtrl* logtext = new wxLogTextCtrl(m_text);
514
515 wxLog* old = wxLog::SetActiveTarget(logtext);
516
517 logtext->LogText("text");
518
519 delete wxLog::SetActiveTarget(old);
520
521 CPPUNIT_ASSERT(!m_text->IsEmpty());
d911dc04
VZ
522}
523
6ce83213
VZ
524void TextCtrlTestCase::PositionToCoords()
525{
526 DoPositionToCoordsTestWithStyle(0);
527}
528
529void TextCtrlTestCase::PositionToCoordsRich()
530{
531 DoPositionToCoordsTestWithStyle(wxTE_RICH);
532}
533
534void TextCtrlTestCase::PositionToCoordsRich2()
535{
536 DoPositionToCoordsTestWithStyle(wxTE_RICH2);
537}
538
539void TextCtrlTestCase::DoPositionToCoordsTestWithStyle(long style)
540{
6ce83213 541 delete m_text;
358fb6ad 542 CreateText(style);
6ce83213
VZ
543
544 // Asking for invalid index should fail.
545 WX_ASSERT_FAILS_WITH_ASSERT( m_text->PositionToCoords(1) );
546
547 // Getting position shouldn't return wxDefaultPosition except if the method
548 // is not implemented at all in the current port.
549 const wxPoint pos0 = m_text->PositionToCoords(0);
550 if ( pos0 == wxDefaultPosition )
551 {
552#if defined(__WXMSW__) || defined(__WXGTK20__)
553 CPPUNIT_FAIL( "PositionToCoords() unexpectedly failed." );
554#endif
555 return;
556 }
557
558 CPPUNIT_ASSERT(pos0.x >= 0);
559 CPPUNIT_ASSERT(pos0.y >= 0);
560
561
562 m_text->SetValue("Hello");
563 wxYield(); // Let GTK layout the control correctly.
564
565 // Position of non-first character should be positive.
566 const long posHello4 = m_text->PositionToCoords(4).x;
567 CPPUNIT_ASSERT( posHello4 > 0 );
568
569 // Asking for position beyond the last character should succeed and return
570 // reasonable result.
571 CPPUNIT_ASSERT( m_text->PositionToCoords(5).x > posHello4 );
572
573 // But asking for the next position should fail.
574 WX_ASSERT_FAILS_WITH_ASSERT( m_text->PositionToCoords(6) );
575
576 // Test getting the coordinates of the last character when it is in the
577 // beginning of a new line to exercise MSW code which has specific logic
578 // for it.
579 m_text->AppendText("\n");
580 const wxPoint posLast = m_text->PositionToCoords(m_text->GetLastPosition());
581 CPPUNIT_ASSERT_EQUAL( pos0.x, posLast.x );
582 CPPUNIT_ASSERT( posLast.y > 0 );
583
584
585 // Add enough contents to the control to make sure it has a scrollbar.
586 m_text->SetValue("First line" + wxString(50, '\n') + "Last line");
587 m_text->SetInsertionPoint(0);
588 wxYield(); // Let GTK layout the control correctly.
589
590 // This shouldn't change anything for the first position coordinates.
591 CPPUNIT_ASSERT_EQUAL( pos0, m_text->PositionToCoords(0) );
592
593 // And the last one must be beyond the window boundary and so not be
594 // visible -- but getting its coordinate should still work.
595 CPPUNIT_ASSERT
596 (
597 m_text->PositionToCoords(m_text->GetLastPosition()).y > TEXT_HEIGHT
598 );
599
600
601 // Now make it scroll to the end and check that the first position now has
602 // negative offset as its above the visible part of the window while the
603 // last position is in its bounds.
604 m_text->SetInsertionPointEnd();
605
606 CPPUNIT_ASSERT( m_text->PositionToCoords(0).y < 0 );
607 CPPUNIT_ASSERT
608 (
609 m_text->PositionToCoords(m_text->GetInsertionPoint()).y <= TEXT_HEIGHT
610 );
611}
612
613
232fdc63 614#endif //wxUSE_TEXTCTRL