]> git.saurik.com Git - wxWidgets.git/blame - tests/controls/textctrltest.cpp
Check for wxUSE_WEBVIEW being defined.
[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
c0d9b217
VZ
34// ----------------------------------------------------------------------------
35// test class
36// ----------------------------------------------------------------------------
37
232fdc63 38class TextCtrlTestCase : public TextEntryTestCase, public CppUnit::TestCase
c0d9b217
VZ
39{
40public:
41 TextCtrlTestCase() { }
42
43 virtual void setUp();
44 virtual void tearDown();
45
46private:
f0f6a32d
VZ
47 virtual wxTextEntry *GetTestEntry() const { return m_text; }
48 virtual wxWindow *GetTestWindow() const { return m_text; }
49
c0d9b217 50 CPPUNIT_TEST_SUITE( TextCtrlTestCase );
f0f6a32d 51 wxTEXT_ENTRY_TESTS();
d911dc04 52 CPPUNIT_TEST( MultiLineReplace );
232fdc63
VZ
53 WXUISIM_TEST( ReadOnly );
54 WXUISIM_TEST( MaxLength );
55 CPPUNIT_TEST( StreamInput );
56 CPPUNIT_TEST( Redirector );
57 //WXUISIM_TEST( ProcessEnter );
58 WXUISIM_TEST( Url );
59 CPPUNIT_TEST( Style );
60 CPPUNIT_TEST( Lines );
61 CPPUNIT_TEST( LogTextCtrl );
6ce83213
VZ
62 CPPUNIT_TEST( PositionToCoords );
63 CPPUNIT_TEST( PositionToCoordsRich );
64 CPPUNIT_TEST( PositionToCoordsRich2 );
c0d9b217
VZ
65 CPPUNIT_TEST_SUITE_END();
66
d911dc04 67 void MultiLineReplace();
232fdc63
VZ
68 void ReadOnly();
69 void MaxLength();
70 void StreamInput();
71 void Redirector();
72 //void ProcessEnter();
73 void Url();
74 void Style();
75 void Lines();
76 void LogTextCtrl();
6ce83213
VZ
77 void PositionToCoords();
78 void PositionToCoordsRich();
79 void PositionToCoordsRich2();
80
81 void DoPositionToCoordsTestWithStyle(long style);
d911dc04 82
c0d9b217 83 wxTextCtrl *m_text;
c0d9b217
VZ
84
85 DECLARE_NO_COPY_CLASS(TextCtrlTestCase)
86};
87
88// register in the unnamed registry so that these tests are run by default
89CPPUNIT_TEST_SUITE_REGISTRATION( TextCtrlTestCase );
90
e3778b4d 91// also include in its own registry so that these tests can be run alone
c0d9b217
VZ
92CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TextCtrlTestCase, "TextCtrlTestCase" );
93
94// ----------------------------------------------------------------------------
95// test initialization
96// ----------------------------------------------------------------------------
97
98void TextCtrlTestCase::setUp()
99{
100 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY);
101}
102
103void TextCtrlTestCase::tearDown()
104{
232fdc63 105 wxDELETE(m_text);
c0d9b217
VZ
106}
107
108// ----------------------------------------------------------------------------
109// tests themselves
110// ----------------------------------------------------------------------------
111
d911dc04
VZ
112void TextCtrlTestCase::MultiLineReplace()
113{
114 // we need a multiline control for this test so recreate it
115 delete m_text;
116 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
117 wxDefaultPosition, wxDefaultSize,
118 wxTE_MULTILINE);
119
120 m_text->SetValue("Hello replace\n"
121 "0123456789012");
122 m_text->SetInsertionPoint(0);
123
124 m_text->Replace(6, 13, "changed");
125
126 CPPUNIT_ASSERT_EQUAL("Hello changed\n"
127 "0123456789012",
128 m_text->GetValue());
129 CPPUNIT_ASSERT_EQUAL(13, m_text->GetInsertionPoint());
130
131 m_text->Replace(13, -1, "");
132 CPPUNIT_ASSERT_EQUAL("Hello changed", m_text->GetValue());
133 CPPUNIT_ASSERT_EQUAL(13, m_text->GetInsertionPoint());
232fdc63
VZ
134
135 delete m_text;
136 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY);
137}
138
139void TextCtrlTestCase::ReadOnly()
140{
141#if wxUSE_UIACTIONSIMULATOR
142 // we need a read only control for this test so recreate it
143 delete m_text;
144 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
145 wxDefaultPosition, wxDefaultSize,
146 wxTE_READONLY);
147
148 wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(),
149 wxTestableFrame);
150
151 EventCounter count(m_text, wxEVT_COMMAND_TEXT_UPDATED);
152
153 m_text->SetFocus();
154
155 wxUIActionSimulator sim;
156 sim.Text("abcdef");
157 wxYield();
158
159 CPPUNIT_ASSERT_EQUAL("", m_text->GetValue());
160 CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount());
161
162 // SetEditable() is supposed to override wxTE_READONLY
163 m_text->SetEditable(true);
164
165 sim.Text("abcdef");
166 wxYield();
167
168 CPPUNIT_ASSERT_EQUAL("abcdef", m_text->GetValue());
169 CPPUNIT_ASSERT_EQUAL(6, frame->GetEventCount());
170
171 delete m_text;
172 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY);
173#endif
174}
175
176void TextCtrlTestCase::MaxLength()
177{
178#if wxUSE_UIACTIONSIMULATOR
179 wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(),
180 wxTestableFrame);
181
182 EventCounter count(m_text, wxEVT_COMMAND_TEXT_UPDATED);
183 EventCounter count1(m_text, wxEVT_COMMAND_TEXT_MAXLEN);
184
185 m_text->SetFocus();
186 m_text->SetMaxLength(10);
187
188 wxUIActionSimulator sim;
189 sim.Text("abcdef");
190 wxYield();
191
192 CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN));
193
194 sim.Text("ghij");
195 wxYield();
196
197 CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN));
198 CPPUNIT_ASSERT_EQUAL(10, frame->GetEventCount(wxEVT_COMMAND_TEXT_UPDATED));
199
200 sim.Text("k");
201 wxYield();
202
203 CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN));
204 CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_UPDATED));
205
206 m_text->SetMaxLength(0);
207
208 sim.Text("k");
209 wxYield();
210
211 CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN));
212 CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount(wxEVT_COMMAND_TEXT_UPDATED));
213#endif
214}
215
216void TextCtrlTestCase::StreamInput()
217{
218#ifndef __WXOSX__
8859c729
VZ
219 {
220 // Ensure we use decimal point and not a comma.
221 char * const locOld = setlocale(LC_NUMERIC, "C");
222 wxON_BLOCK_EXIT2( setlocale, (int)LC_NUMERIC, locOld );
223
224 *m_text << "stringinput"
225 << 10
226 << 1000L
227 << 3.14f
228 << 2.71
229 << 'a'
230 << L'b';
231 }
232fdc63
VZ
232
233 CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71ab", m_text->GetValue());
234
235 m_text->SetValue("");
236
237#if wxHAS_TEXT_WINDOW_STREAM
238
239 std::ostream stream(m_text);
240
241 // We don't test a wide character as this is not a wide stream
242 stream << "stringinput"
243 << 10
244 << 1000L
245 << 3.14f
246 << 2.71
247 << 'a';
248
249 stream.flush();
250
251 CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71a", m_text->GetValue());
252
8859c729
VZ
253#endif // wxHAS_TEXT_WINDOW_STREAM
254#endif // !__WXOSX__
232fdc63
VZ
255}
256
257void TextCtrlTestCase::Redirector()
258{
259#if wxHAS_TEXT_WINDOW_STREAM && wxUSE_STD_IOSTREAM
260
261 wxStreamToTextRedirector redirect(m_text);
262
263 std::cout << "stringinput"
264 << 10
265 << 1000L
266 << 3.14f
267 << 2.71
268 << 'a';
269
270 CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71a", m_text->GetValue());
271
272#endif
273}
274
275#if 0
276void TextCtrlTestCase::ProcessEnter()
277{
278#if wxUSE_UIACTIONSIMULATOR
279 wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(),
280 wxTestableFrame);
281
282 EventCounter count(m_text, wxEVT_COMMAND_TEXT_ENTER);
283
284 m_text->SetFocus();
285
286 wxUIActionSimulator sim;
287 sim.Char(WXK_RETURN);
288 wxYield();
289
290 CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_ENTER));
291
292 // we need a text control with wxTE_PROCESS_ENTER for this test
293 delete m_text;
294 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
295 wxDefaultPosition, wxDefaultSize,
296 wxTE_PROCESS_ENTER);
297
298 m_text->SetFocus();
299
300 sim.Char(WXK_RETURN);
301 wxYield();
302
303 CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount(wxEVT_COMMAND_TEXT_ENTER));
304#endif
305}
306#endif
307
308void TextCtrlTestCase::Url()
309{
310#if wxUSE_UIACTIONSIMULATOR && defined(__WXMSW__)
311 delete m_text;
312 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
313 wxDefaultPosition, wxDefaultSize,
314 wxTE_MULTILINE | wxTE_RICH | wxTE_AUTO_URL);
315
316 wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(),
317 wxTestableFrame);
318
319 EventCounter count(m_text, wxEVT_COMMAND_TEXT_URL);
320
321 m_text->AppendText("http://www.wxwidgets.org");
322
323 wxUIActionSimulator sim;
324 sim.MouseMove(m_text->ClientToScreen(wxPoint(5, 5)));
325 sim.MouseClick();
326 wxYield();
327
328 CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount());
329#endif
330}
331
332void TextCtrlTestCase::Style()
333{
334#ifndef __WXOSX__
335 delete m_text;
336 // We need wxTE_RICH under windows for style support
337 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
338 wxDefaultPosition, wxDefaultSize, wxTE_RICH);
339
340 // Red text on a white background
341 m_text->SetDefaultStyle(wxTextAttr(*wxRED, *wxWHITE));
342
343 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxRED);
344 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(),
345 *wxWHITE);
346
347 m_text->AppendText("red on white ");
348
349 // Red text on a grey background
350 m_text->SetDefaultStyle(wxTextAttr(wxNullColour, *wxLIGHT_GREY));
351
352 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxRED);
353 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(),
354 *wxLIGHT_GREY);
355
356 m_text->AppendText("red on grey ");
357
358 // Blue text on a grey background
359 m_text->SetDefaultStyle(wxTextAttr(*wxBLUE));
360
361
362 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxBLUE);
363 CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(),
364 *wxLIGHT_GREY);
365
366 m_text->AppendText("blue on grey");
367
368 // Get getting the style at a specific location
369 wxTextAttr style;
370
371 // We have to check that styles are supported
372 if(m_text->GetStyle(3, style))
373 {
374 CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED);
375 CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE);
376 }
377
378 // And then setting the style
379 if(m_text->SetStyle(15, 18, style))
380 {
381 m_text->GetStyle(17, style);
382
383 CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED);
384 CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE);
385 }
386#endif
387}
388
389void TextCtrlTestCase::Lines()
390{
232fdc63
VZ
391 delete m_text;
392 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
393 wxDefaultPosition, wxSize(400, 200), wxTE_MULTILINE | wxTE_DONTWRAP);
394
395 m_text->SetValue("line1\nline2\nlong long line 3");
396 m_text->Refresh();
397 m_text->Update();
398
399 CPPUNIT_ASSERT_EQUAL(3, m_text->GetNumberOfLines());
400 CPPUNIT_ASSERT_EQUAL(5, m_text->GetLineLength(0));
401 CPPUNIT_ASSERT_EQUAL("line2", m_text->GetLineText(1));
402 CPPUNIT_ASSERT_EQUAL(16, m_text->GetLineLength(2));
403
404 m_text->AppendText("\n\nMore text on line 5");
405
406 CPPUNIT_ASSERT_EQUAL(5, m_text->GetNumberOfLines());
407 CPPUNIT_ASSERT_EQUAL(0, m_text->GetLineLength(3));
408 CPPUNIT_ASSERT_EQUAL("", m_text->GetLineText(3));
567e5e47
VZ
409
410 // Verify that wrapped lines count as 2 lines.
411 //
412 // This currently doesn't work neither in wxGTK nor wxOSX/Cocoa, see
413 // #12366, where GetNumberOfLines() always returns the number of logical,
414 // not physical, lines.
415 m_text->AppendText("\n" + wxString(50, '1') + ' ' + wxString(50, '2'));
416#if defined(__WXGTK__) || defined(__WXOSX_COCOA__)
417 CPPUNIT_ASSERT_EQUAL(6, m_text->GetNumberOfLines());
418#else
419 CPPUNIT_ASSERT_EQUAL(7, m_text->GetNumberOfLines());
232fdc63
VZ
420#endif
421}
422
423void TextCtrlTestCase::LogTextCtrl()
424{
425 delete m_text;
426 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
427 wxDefaultPosition, wxSize(400, 200),
428 wxTE_MULTILINE);
429
430 CPPUNIT_ASSERT(m_text->IsEmpty());
431
432 wxLogTextCtrl* logtext = new wxLogTextCtrl(m_text);
433
434 wxLog* old = wxLog::SetActiveTarget(logtext);
435
436 logtext->LogText("text");
437
438 delete wxLog::SetActiveTarget(old);
439
440 CPPUNIT_ASSERT(!m_text->IsEmpty());
d911dc04
VZ
441}
442
6ce83213
VZ
443void TextCtrlTestCase::PositionToCoords()
444{
445 DoPositionToCoordsTestWithStyle(0);
446}
447
448void TextCtrlTestCase::PositionToCoordsRich()
449{
450 DoPositionToCoordsTestWithStyle(wxTE_RICH);
451}
452
453void TextCtrlTestCase::PositionToCoordsRich2()
454{
455 DoPositionToCoordsTestWithStyle(wxTE_RICH2);
456}
457
458void TextCtrlTestCase::DoPositionToCoordsTestWithStyle(long style)
459{
460 static const int TEXT_HEIGHT = 200;
461
462 delete m_text;
463 m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
464 wxDefaultPosition, wxSize(400, TEXT_HEIGHT),
465 wxTE_MULTILINE | style);
466
467 // Asking for invalid index should fail.
468 WX_ASSERT_FAILS_WITH_ASSERT( m_text->PositionToCoords(1) );
469
470 // Getting position shouldn't return wxDefaultPosition except if the method
471 // is not implemented at all in the current port.
472 const wxPoint pos0 = m_text->PositionToCoords(0);
473 if ( pos0 == wxDefaultPosition )
474 {
475#if defined(__WXMSW__) || defined(__WXGTK20__)
476 CPPUNIT_FAIL( "PositionToCoords() unexpectedly failed." );
477#endif
478 return;
479 }
480
481 CPPUNIT_ASSERT(pos0.x >= 0);
482 CPPUNIT_ASSERT(pos0.y >= 0);
483
484
485 m_text->SetValue("Hello");
486 wxYield(); // Let GTK layout the control correctly.
487
488 // Position of non-first character should be positive.
489 const long posHello4 = m_text->PositionToCoords(4).x;
490 CPPUNIT_ASSERT( posHello4 > 0 );
491
492 // Asking for position beyond the last character should succeed and return
493 // reasonable result.
494 CPPUNIT_ASSERT( m_text->PositionToCoords(5).x > posHello4 );
495
496 // But asking for the next position should fail.
497 WX_ASSERT_FAILS_WITH_ASSERT( m_text->PositionToCoords(6) );
498
499 // Test getting the coordinates of the last character when it is in the
500 // beginning of a new line to exercise MSW code which has specific logic
501 // for it.
502 m_text->AppendText("\n");
503 const wxPoint posLast = m_text->PositionToCoords(m_text->GetLastPosition());
504 CPPUNIT_ASSERT_EQUAL( pos0.x, posLast.x );
505 CPPUNIT_ASSERT( posLast.y > 0 );
506
507
508 // Add enough contents to the control to make sure it has a scrollbar.
509 m_text->SetValue("First line" + wxString(50, '\n') + "Last line");
510 m_text->SetInsertionPoint(0);
511 wxYield(); // Let GTK layout the control correctly.
512
513 // This shouldn't change anything for the first position coordinates.
514 CPPUNIT_ASSERT_EQUAL( pos0, m_text->PositionToCoords(0) );
515
516 // And the last one must be beyond the window boundary and so not be
517 // visible -- but getting its coordinate should still work.
518 CPPUNIT_ASSERT
519 (
520 m_text->PositionToCoords(m_text->GetLastPosition()).y > TEXT_HEIGHT
521 );
522
523
524 // Now make it scroll to the end and check that the first position now has
525 // negative offset as its above the visible part of the window while the
526 // last position is in its bounds.
527 m_text->SetInsertionPointEnd();
528
529 CPPUNIT_ASSERT( m_text->PositionToCoords(0).y < 0 );
530 CPPUNIT_ASSERT
531 (
532 m_text->PositionToCoords(m_text->GetInsertionPoint()).y <= TEXT_HEIGHT
533 );
534}
535
536
232fdc63 537#endif //wxUSE_TEXTCTRL