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