/////////////////////////////////////////////////////////////////////////////// // Name: tests/controls/notebooktest.cpp // Purpose: wxNotebook unit test // Author: Steven Lamerton // Created: 2010-07-02 // Copyright: (c) 2010 Steven Lamerton /////////////////////////////////////////////////////////////////////////////// #include "testprec.h" #if wxUSE_NOTEBOOK #ifndef WX_PRECOMP #include "wx/app.h" #include "wx/panel.h" #endif // WX_PRECOMP #include "wx/notebook.h" #include "asserthelper.h" #include "bookctrlbasetest.h" #include "testableframe.h" #include class NotebookTestCase : public BookCtrlBaseTestCase, public CppUnit::TestCase { public: NotebookTestCase() { m_notebook = nullptr; m_numPageChanges = 0; } virtual void setUp() override; virtual void tearDown() override; private: virtual wxBookCtrlBase *GetBase() const override { return m_notebook; } virtual wxEventType GetChangedEvent() const override { return wxEVT_NOTEBOOK_PAGE_CHANGED; } virtual wxEventType GetChangingEvent() const override { return wxEVT_NOTEBOOK_PAGE_CHANGING; } CPPUNIT_TEST_SUITE( NotebookTestCase ); wxBOOK_CTRL_BASE_TESTS(); CPPUNIT_TEST( Image ); CPPUNIT_TEST( RowCount ); CPPUNIT_TEST( NoEventsOnDestruction ); CPPUNIT_TEST( GetTabRect ); CPPUNIT_TEST( HitTestFlags ); CPPUNIT_TEST_SUITE_END(); void RowCount(); void NoEventsOnDestruction(); void GetTabRect(); void HitTestFlags(); void OnPageChanged(wxNotebookEvent&) { m_numPageChanges++; } wxNotebook *m_notebook; int m_numPageChanges; wxDECLARE_NO_COPY_CLASS(NotebookTestCase); }; // register in the unnamed registry so that these tests are run by default CPPUNIT_TEST_SUITE_REGISTRATION( NotebookTestCase ); // also include in its own registry so that these tests can be run alone CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( NotebookTestCase, "NotebookTestCase" ); void NotebookTestCase::setUp() { m_notebook = new wxNotebook(wxTheApp->GetTopWindow(), wxID_ANY, wxDefaultPosition, wxSize(400, 200)); AddPanels(); } void NotebookTestCase::tearDown() { wxDELETE(m_notebook); } void NotebookTestCase::RowCount() { CPPUNIT_ASSERT_EQUAL(1, m_notebook->GetRowCount()); #ifdef __WXMSW__ wxDELETE(m_notebook); m_notebook = new wxNotebook(wxTheApp->GetTopWindow(), wxID_ANY, wxDefaultPosition, wxSize(400, 200), wxNB_MULTILINE); for( unsigned int i = 0; i < 10; i++ ) { m_notebook->AddPage(new wxPanel(m_notebook), "Panel", false, 0); } CPPUNIT_ASSERT( m_notebook->GetRowCount() != 1 ); #endif } void NotebookTestCase::NoEventsOnDestruction() { // We can't use EventCounter helper here as it doesn't deal with the window // it's connected to being destroyed during its life-time, so do it // manually. m_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &NotebookTestCase::OnPageChanged, this); // Normally deleting a page before the selected one results in page // selection changing and the corresponding event. m_notebook->DeletePage(static_cast(0)); CHECK( m_numPageChanges == 1 ); // But deleting the entire control shouldn't generate any events, yet it // used to do under GTK+ 3 when a page different from the first one was // selected. m_notebook->ChangeSelection(1); m_notebook->Destroy(); m_notebook = nullptr; CHECK( m_numPageChanges == 1 ); } TEST_CASE("wxNotebook::AddPageEvents", "[wxNotebook][AddPage][event]") { wxNotebook* const notebook = new wxNotebook(wxTheApp->GetTopWindow(), wxID_ANY, wxDefaultPosition, wxSize(400, 200)); std::unique_ptr cleanup(notebook); CHECK( notebook->GetSelection() == wxNOT_FOUND ); EventCounter countPageChanging(notebook, wxEVT_NOTEBOOK_PAGE_CHANGING); EventCounter countPageChanged(notebook, wxEVT_NOTEBOOK_PAGE_CHANGED); // Add the first page, it is special. notebook->AddPage(new wxPanel(notebook), "Initial page"); // The selection should have been changed. CHECK( notebook->GetSelection() == 0 ); // But no events should have been generated. CHECK( countPageChanging.GetCount() == 0 ); CHECK( countPageChanged.GetCount() == 0 ); // Add another page without selecting it. notebook->AddPage(new wxPanel(notebook), "Unselected page"); // Selection shouldn't have changed. CHECK( notebook->GetSelection() == 0 ); // And no events should have been generated, of course. CHECK( countPageChanging.GetCount() == 0 ); CHECK( countPageChanged.GetCount() == 0 ); // Finally add another page and do select it. notebook->AddPage(new wxPanel(notebook), "Selected page", true); // It should have become selected. CHECK( notebook->GetSelection() == 2 ); // And events for the selection change should have been generated. CHECK( countPageChanging.GetCount() == 1 ); CHECK( countPageChanged.GetCount() == 1 ); } void NotebookTestCase::GetTabRect() { wxNotebook *notebook = new wxNotebook(wxTheApp->GetTopWindow(), wxID_ANY, wxDefaultPosition, wxSize(400, 200)); std::unique_ptr cleanup(notebook); notebook->AddPage(new wxPanel(notebook), "Page"); // This function is only really implemented for wxMSW and wxUniv currently. #if defined(__WXMSW__) || defined(__WXUNIVERSAL__) // Create many pages, so that at least some of the are not visible. for ( size_t i = 0; i < 30; i++ ) notebook->AddPage(new wxPanel(notebook), "Page"); const wxRect rectPage = notebook->GetTabRect(0); REQUIRE(rectPage.width != 0); REQUIRE(rectPage.height != 0); int x = rectPage.x + rectPage.width; for ( size_t i = 1; i < notebook->GetPageCount(); i++ ) { wxRect r = notebook->GetTabRect(i); if (wxIsRunningUnderWine()) { // Wine behaves different than Windows. Windows reports the size of a // tab even if it is not visible while Wine returns an empty rectangle. if ( r == wxRect() ) { WARN("Skipping test for pages after " << i << " under Wine."); break; } } INFO("Page #" << i << ": rect=" << r); REQUIRE(r.x == x); REQUIRE(r.y == rectPage.y); REQUIRE(r.width == rectPage.width); REQUIRE(r.height == rectPage.height); x += r.width; } #else // !(__WXMSW__ || __WXUNIVERSAL__) WX_ASSERT_FAILS_WITH_ASSERT( notebook->GetTabRect(0) ); #endif // ports } void NotebookTestCase::HitTestFlags() { std::unique_ptr notebook; #if defined(__WXMSW__) || defined(__WXUNIVERSAL__) long style = 0; SECTION("Top") { style = wxBK_TOP; } SECTION("Bottom") { style = wxBK_BOTTOM; } SECTION("Left") { style = wxBK_LEFT; } SECTION("Right") { style = wxBK_RIGHT; } INFO("Style=" << style); const bool isVertical = style == wxBK_TOP || style == wxBK_BOTTOM; // HitTest() uses TCM_HITTEST for the vertical orientations and it doesn't // seem to work correctly under Wine, so skip the test there (for the // horizontal tabs we use our own code which does work even under Wine). if ( isVertical && wxIsRunningUnderWine() ) return; notebook.reset(new wxNotebook(wxTheApp->GetTopWindow(), wxID_ANY, wxPoint(0, 0), wxSize(400, 200), style)); // Simulate an icon of standard size, its contents doesn't matter. const wxSize imageSize(16, 16); wxBookCtrlBase::Images images; images.push_back(wxBitmapBundle::FromBitmap(wxBitmap(imageSize))); notebook->SetImages(images); notebook->AddPage(new wxPanel(notebook.get()), "First Page", false, 0); const wxRect r = notebook->GetTabRect(0); INFO("Rect=" << r); wxPoint pt; if ( isVertical ) pt.y = r.y + r.height / 2; else pt.x = r.x + r.width / 2; int nowhere = 0; int onIcon = 0; int onLabel = 0; int onItem = 0; const int d = isVertical ? r.width : r.height; for (int i = 0; i < d; i++) { long flags = 0; notebook->HitTest(pt, &flags); if (flags & wxBK_HITTEST_NOWHERE) nowhere++; if (flags & wxBK_HITTEST_ONICON) onIcon++; if (flags & wxBK_HITTEST_ONLABEL) onLabel++; if (flags & wxBK_HITTEST_ONITEM) onItem++; if (isVertical) pt.x++; else pt.y++; } CHECK(nowhere); CHECK(onIcon); CHECK(onLabel); CHECK(onItem); #else // !(__WXMSW__ || __WXUNIVERSAL__) notebook.reset(new wxNotebook(wxTheApp->GetTopWindow(), wxID_ANY, wxDefaultPosition, wxSize(400, 200))); notebook->AddPage(new wxPanel(notebook.get()), "First Page"); WX_ASSERT_FAILS_WITH_ASSERT(notebook->GetTabRect(0)); #endif // ports } #endif //wxUSE_NOTEBOOK