X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b2b0bee6d822b05fea419e8bf24ab4009cb17ac4..c29c95fe24973b94fd724db767193171ca7c513d:/tests/controls/textctrltest.cpp diff --git a/tests/controls/textctrltest.cpp b/tests/controls/textctrltest.cpp index 04e5939a5e..86f0fbee7a 100644 --- a/tests/controls/textctrltest.cpp +++ b/tests/controls/textctrltest.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: tests/textctrl/textctrltest.cpp +// Name: tests/controls/textctrltest.cpp // Purpose: wxTextCtrl unit test // Author: Vadim Zeitlin // Created: 2007-09-25 @@ -13,6 +13,8 @@ #include "testprec.h" +#if wxUSE_TEXTCTRL + #ifdef __BORLANDC__ #pragma hdrstop #endif @@ -22,11 +24,18 @@ #include "wx/textctrl.h" #endif // WX_PRECOMP +#include "wx/scopeguard.h" + +#include "textentrytest.h" +#include "testableframe.h" +#include "asserthelper.h" +#include "wx/uiaction.h" + // ---------------------------------------------------------------------------- // test class // ---------------------------------------------------------------------------- -class TextCtrlTestCase : public CppUnit::TestCase +class TextCtrlTestCase : public TextEntryTestCase, public CppUnit::TestCase { public: TextCtrlTestCase() { } @@ -35,22 +44,43 @@ public: virtual void tearDown(); private: + virtual wxTextEntry *GetTestEntry() const { return m_text; } + virtual wxWindow *GetTestWindow() const { return m_text; } + CPPUNIT_TEST_SUITE( TextCtrlTestCase ); - CPPUNIT_TEST( SetValue ); - CPPUNIT_TEST( TextChangeEvents ); - CPPUNIT_TEST( Selection ); + wxTEXT_ENTRY_TESTS(); + CPPUNIT_TEST( MultiLineReplace ); + WXUISIM_TEST( ReadOnly ); + WXUISIM_TEST( MaxLength ); + CPPUNIT_TEST( StreamInput ); + CPPUNIT_TEST( Redirector ); + //WXUISIM_TEST( ProcessEnter ); + WXUISIM_TEST( Url ); + CPPUNIT_TEST( Style ); + CPPUNIT_TEST( Lines ); + CPPUNIT_TEST( LogTextCtrl ); + CPPUNIT_TEST( PositionToCoords ); + CPPUNIT_TEST( PositionToCoordsRich ); + CPPUNIT_TEST( PositionToCoordsRich2 ); CPPUNIT_TEST_SUITE_END(); - void SetValue(); - void TextChangeEvents(); - void Selection(); - - // Selection() test helper: verify that selection is as described by the - // function parameters - void AssertSelection(int from, int to, const char *sel); + void MultiLineReplace(); + void ReadOnly(); + void MaxLength(); + void StreamInput(); + void Redirector(); + //void ProcessEnter(); + void Url(); + void Style(); + void Lines(); + void LogTextCtrl(); + void PositionToCoords(); + void PositionToCoordsRich(); + void PositionToCoordsRich2(); + + void DoPositionToCoordsTestWithStyle(long style); wxTextCtrl *m_text; - wxFrame *m_frame; DECLARE_NO_COPY_CLASS(TextCtrlTestCase) }; @@ -58,7 +88,7 @@ private: // register in the unnamed registry so that these tests are run by default CPPUNIT_TEST_SUITE_REGISTRATION( TextCtrlTestCase ); -// also include in it's own registry so that these tests can be run alone +// also include in its own registry so that these tests can be run alone CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TextCtrlTestCase, "TextCtrlTestCase" ); // ---------------------------------------------------------------------------- @@ -72,113 +102,426 @@ void TextCtrlTestCase::setUp() void TextCtrlTestCase::tearDown() { - delete m_text; - m_text = NULL; + wxDELETE(m_text); } // ---------------------------------------------------------------------------- // tests themselves // ---------------------------------------------------------------------------- -void TextCtrlTestCase::SetValue() +void TextCtrlTestCase::MultiLineReplace() +{ + // we need a multiline control for this test so recreate it + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE); + + m_text->SetValue("Hello replace\n" + "0123456789012"); + m_text->SetInsertionPoint(0); + + m_text->Replace(6, 13, "changed"); + + CPPUNIT_ASSERT_EQUAL("Hello changed\n" + "0123456789012", + m_text->GetValue()); + CPPUNIT_ASSERT_EQUAL(13, m_text->GetInsertionPoint()); + + m_text->Replace(13, -1, ""); + CPPUNIT_ASSERT_EQUAL("Hello changed", m_text->GetValue()); + CPPUNIT_ASSERT_EQUAL(13, m_text->GetInsertionPoint()); + + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY); +} + +void TextCtrlTestCase::ReadOnly() +{ +#if wxUSE_UIACTIONSIMULATOR + // we need a read only control for this test so recreate it + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxDefaultSize, + wxTE_READONLY); + + wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(), + wxTestableFrame); + + EventCounter count(m_text, wxEVT_COMMAND_TEXT_UPDATED); + + m_text->SetFocus(); + + wxUIActionSimulator sim; + sim.Text("abcdef"); + wxYield(); + + CPPUNIT_ASSERT_EQUAL("", m_text->GetValue()); + CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount()); + + // SetEditable() is supposed to override wxTE_READONLY + m_text->SetEditable(true); + + sim.Text("abcdef"); + wxYield(); + + CPPUNIT_ASSERT_EQUAL("abcdef", m_text->GetValue()); + CPPUNIT_ASSERT_EQUAL(6, frame->GetEventCount()); + + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY); +#endif +} + +void TextCtrlTestCase::MaxLength() { - CPPUNIT_ASSERT( m_text->IsEmpty() ); +#if wxUSE_UIACTIONSIMULATOR + wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(), + wxTestableFrame); - m_text->SetValue("foo"); - CPPUNIT_ASSERT_EQUAL( "foo", m_text->GetValue() ); + EventCounter count(m_text, wxEVT_COMMAND_TEXT_UPDATED); + EventCounter count1(m_text, wxEVT_COMMAND_TEXT_MAXLEN); + + m_text->SetFocus(); + m_text->SetMaxLength(10); + + wxUIActionSimulator sim; + sim.Text("abcdef"); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN)); + + sim.Text("ghij"); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN)); + CPPUNIT_ASSERT_EQUAL(10, frame->GetEventCount(wxEVT_COMMAND_TEXT_UPDATED)); + + sim.Text("k"); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN)); + CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_UPDATED)); + + m_text->SetMaxLength(0); + + sim.Text("k"); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_MAXLEN)); + CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount(wxEVT_COMMAND_TEXT_UPDATED)); +#endif +} + +void TextCtrlTestCase::StreamInput() +{ +#ifndef __WXOSX__ + { + // Ensure we use decimal point and not a comma. + char * const locOld = setlocale(LC_NUMERIC, "C"); + wxON_BLOCK_EXIT2( setlocale, (int)LC_NUMERIC, locOld ); + + *m_text << "stringinput" + << 10 + << 1000L + << 3.14f + << 2.71 + << 'a' + << L'b'; + } + + CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71ab", m_text->GetValue()); m_text->SetValue(""); - CPPUNIT_ASSERT( m_text->IsEmpty() ); - m_text->SetValue("hi"); - CPPUNIT_ASSERT_EQUAL( "hi", m_text->GetValue() ); +#if wxHAS_TEXT_WINDOW_STREAM + + std::ostream stream(m_text); + + // We don't test a wide character as this is not a wide stream + stream << "stringinput" + << 10 + << 1000L + << 3.14f + << 2.71 + << 'a'; + + stream.flush(); + + CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71a", m_text->GetValue()); + +#endif // wxHAS_TEXT_WINDOW_STREAM +#endif // !__WXOSX__ +} + +void TextCtrlTestCase::Redirector() +{ +#if wxHAS_TEXT_WINDOW_STREAM && wxUSE_STD_IOSTREAM + + wxStreamToTextRedirector redirect(m_text); + + std::cout << "stringinput" + << 10 + << 1000L + << 3.14f + << 2.71 + << 'a'; + + CPPUNIT_ASSERT_EQUAL("stringinput1010003.142.71a", m_text->GetValue()); + +#endif +} + +#if 0 +void TextCtrlTestCase::ProcessEnter() +{ +#if wxUSE_UIACTIONSIMULATOR + wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(), + wxTestableFrame); + + EventCounter count(m_text, wxEVT_COMMAND_TEXT_ENTER); + + m_text->SetFocus(); + + wxUIActionSimulator sim; + sim.Char(WXK_RETURN); + wxYield(); - m_text->SetValue("bye"); - CPPUNIT_ASSERT_EQUAL( "bye", m_text->GetValue() ); + CPPUNIT_ASSERT_EQUAL(0, frame->GetEventCount(wxEVT_COMMAND_TEXT_ENTER)); + + // we need a text control with wxTE_PROCESS_ENTER for this test + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxDefaultSize, + wxTE_PROCESS_ENTER); + + m_text->SetFocus(); + + sim.Char(WXK_RETURN); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount(wxEVT_COMMAND_TEXT_ENTER)); +#endif } +#endif -void TextCtrlTestCase::TextChangeEvents() +void TextCtrlTestCase::Url() { - class TextTestEventHandler : public wxEvtHandler +#if wxUSE_UIACTIONSIMULATOR && defined(__WXMSW__) + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxTE_RICH | wxTE_AUTO_URL); + + wxTestableFrame* frame = wxStaticCast(wxTheApp->GetTopWindow(), + wxTestableFrame); + + EventCounter count(m_text, wxEVT_COMMAND_TEXT_URL); + + m_text->AppendText("http://www.wxwidgets.org"); + + wxUIActionSimulator sim; + sim.MouseMove(m_text->ClientToScreen(wxPoint(5, 5))); + sim.MouseClick(); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(1, frame->GetEventCount()); +#endif +} + +void TextCtrlTestCase::Style() +{ +#ifndef __WXOSX__ + delete m_text; + // We need wxTE_RICH under windows for style support + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxDefaultSize, wxTE_RICH); + + // Red text on a white background + m_text->SetDefaultStyle(wxTextAttr(*wxRED, *wxWHITE)); + + CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxRED); + CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(), + *wxWHITE); + + m_text->AppendText("red on white "); + + // Red text on a grey background + m_text->SetDefaultStyle(wxTextAttr(wxNullColour, *wxLIGHT_GREY)); + + CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxRED); + CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(), + *wxLIGHT_GREY); + + m_text->AppendText("red on grey "); + + // Blue text on a grey background + m_text->SetDefaultStyle(wxTextAttr(*wxBLUE)); + + + CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetTextColour(), *wxBLUE); + CPPUNIT_ASSERT_EQUAL(m_text->GetDefaultStyle().GetBackgroundColour(), + *wxLIGHT_GREY); + + m_text->AppendText("blue on grey"); + + // Get getting the style at a specific location + wxTextAttr style; + + // We have to check that styles are supported + if(m_text->GetStyle(3, style)) { - public: - TextTestEventHandler() { m_events = 0; } + CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED); + CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE); + } - // calling this automatically resets the events counter - int GetEvents() - { - const int events = m_events; - m_events = 0; - return events; - } + // And then setting the style + if(m_text->SetStyle(15, 18, style)) + { + m_text->GetStyle(17, style); - void OnText(wxCommandEvent& WXUNUSED(event)) { m_events++; } + CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED); + CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE); + } +#endif +} - private: - int m_events; - } handler; +void TextCtrlTestCase::Lines() +{ +#ifndef __WXOSX__ + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxSize(400, 200), wxTE_MULTILINE | wxTE_DONTWRAP); - m_text->Connect(wxEVT_COMMAND_TEXT_UPDATED, - wxCommandEventHandler(TextTestEventHandler::OnText), - NULL, - &handler); + m_text->SetValue("line1\nline2\nlong long line 3"); + m_text->Refresh(); + m_text->Update(); - // notice that SetValue() generates an event even if the text didn't change - m_text->SetValue(""); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + CPPUNIT_ASSERT_EQUAL(3, m_text->GetNumberOfLines()); + CPPUNIT_ASSERT_EQUAL(5, m_text->GetLineLength(0)); + CPPUNIT_ASSERT_EQUAL("line2", m_text->GetLineText(1)); + CPPUNIT_ASSERT_EQUAL(16, m_text->GetLineLength(2)); - m_text->SetValue("foo"); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + m_text->AppendText("\n\nMore text on line 5"); - m_text->SetValue("foo"); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + CPPUNIT_ASSERT_EQUAL(5, m_text->GetNumberOfLines()); + CPPUNIT_ASSERT_EQUAL(0, m_text->GetLineLength(3)); + CPPUNIT_ASSERT_EQUAL("", m_text->GetLineText(3)); +#endif +} - m_text->ChangeValue("bar"); - CPPUNIT_ASSERT_EQUAL( 0, handler.GetEvents() ); +void TextCtrlTestCase::LogTextCtrl() +{ + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxSize(400, 200), + wxTE_MULTILINE); + + CPPUNIT_ASSERT(m_text->IsEmpty()); - m_text->AppendText("bar"); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + wxLogTextCtrl* logtext = new wxLogTextCtrl(m_text); - m_text->Replace(3, 6, "baz"); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + wxLog* old = wxLog::SetActiveTarget(logtext); - m_text->Remove(0, 3); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + logtext->LogText("text"); - m_text->WriteText("foo"); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + delete wxLog::SetActiveTarget(old); - m_text->Clear(); - CPPUNIT_ASSERT_EQUAL( 1, handler.GetEvents() ); + CPPUNIT_ASSERT(!m_text->IsEmpty()); } -void TextCtrlTestCase::AssertSelection(int from, int to, const char *sel) +void TextCtrlTestCase::PositionToCoords() { - CPPUNIT_ASSERT( m_text->HasSelection() ); + DoPositionToCoordsTestWithStyle(0); +} - long fromReal, - toReal; - m_text->GetSelection(&fromReal, &toReal); - CPPUNIT_ASSERT_EQUAL( from, fromReal ); - CPPUNIT_ASSERT_EQUAL( to, toReal ); - CPPUNIT_ASSERT_EQUAL( sel, m_text->GetStringSelection() ); +void TextCtrlTestCase::PositionToCoordsRich() +{ + DoPositionToCoordsTestWithStyle(wxTE_RICH); +} - CPPUNIT_ASSERT_EQUAL( from, m_text->GetInsertionPoint() ); +void TextCtrlTestCase::PositionToCoordsRich2() +{ + DoPositionToCoordsTestWithStyle(wxTE_RICH2); } -void TextCtrlTestCase::Selection() +void TextCtrlTestCase::DoPositionToCoordsTestWithStyle(long style) { - m_text->SetValue("0123456789"); + static const int TEXT_HEIGHT = 200; - m_text->SetSelection(2, 4); - AssertSelection(2, 4, "23"); // not "234"! + delete m_text; + m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxSize(400, TEXT_HEIGHT), + wxTE_MULTILINE | style); - m_text->SetSelection(3, -1); - AssertSelection(3, 10, "3456789"); + // Asking for invalid index should fail. + WX_ASSERT_FAILS_WITH_ASSERT( m_text->PositionToCoords(1) ); - m_text->SelectAll(); - AssertSelection(0, 10, "0123456789"); + // Getting position shouldn't return wxDefaultPosition except if the method + // is not implemented at all in the current port. + const wxPoint pos0 = m_text->PositionToCoords(0); + if ( pos0 == wxDefaultPosition ) + { +#if defined(__WXMSW__) || defined(__WXGTK20__) + CPPUNIT_FAIL( "PositionToCoords() unexpectedly failed." ); +#endif + return; + } + + CPPUNIT_ASSERT(pos0.x >= 0); + CPPUNIT_ASSERT(pos0.y >= 0); + + + m_text->SetValue("Hello"); + wxYield(); // Let GTK layout the control correctly. + + // Position of non-first character should be positive. + const long posHello4 = m_text->PositionToCoords(4).x; + CPPUNIT_ASSERT( posHello4 > 0 ); + + // Asking for position beyond the last character should succeed and return + // reasonable result. + CPPUNIT_ASSERT( m_text->PositionToCoords(5).x > posHello4 ); + + // But asking for the next position should fail. + WX_ASSERT_FAILS_WITH_ASSERT( m_text->PositionToCoords(6) ); + + // Test getting the coordinates of the last character when it is in the + // beginning of a new line to exercise MSW code which has specific logic + // for it. + m_text->AppendText("\n"); + const wxPoint posLast = m_text->PositionToCoords(m_text->GetLastPosition()); + CPPUNIT_ASSERT_EQUAL( pos0.x, posLast.x ); + CPPUNIT_ASSERT( posLast.y > 0 ); - m_text->SetSelection(0, 0); - CPPUNIT_ASSERT( !m_text->HasSelection() ); + + // Add enough contents to the control to make sure it has a scrollbar. + m_text->SetValue("First line" + wxString(50, '\n') + "Last line"); + m_text->SetInsertionPoint(0); + wxYield(); // Let GTK layout the control correctly. + + // This shouldn't change anything for the first position coordinates. + CPPUNIT_ASSERT_EQUAL( pos0, m_text->PositionToCoords(0) ); + + // And the last one must be beyond the window boundary and so not be + // visible -- but getting its coordinate should still work. + CPPUNIT_ASSERT + ( + m_text->PositionToCoords(m_text->GetLastPosition()).y > TEXT_HEIGHT + ); + + + // Now make it scroll to the end and check that the first position now has + // negative offset as its above the visible part of the window while the + // last position is in its bounds. + m_text->SetInsertionPointEnd(); + + CPPUNIT_ASSERT( m_text->PositionToCoords(0).y < 0 ); + CPPUNIT_ASSERT + ( + m_text->PositionToCoords(m_text->GetInsertionPoint()).y <= TEXT_HEIGHT + ); } + + +#endif //wxUSE_TEXTCTRL