/////////////////////////////////////////////////////////////////////////////// // Name: tests/controls/treectrltest.cpp // Purpose: wxTreeCtrl unit test // Author: Vadim Zeitlin // Created: 2008-11-26 // Copyright: (c) 2008 Vadim Zeitlin // (c) 2010 Steven Lamerton /////////////////////////////////////////////////////////////////////////////// // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- #include "testprec.h" #if wxUSE_TREECTRL #ifndef WX_PRECOMP #include "wx/app.h" #endif // WX_PRECOMP #include "wx/artprov.h" #include "wx/imaglist.h" #include "wx/treectrl.h" #include "wx/uiaction.h" #include "testableframe.h" // ---------------------------------------------------------------------------- // test class // ---------------------------------------------------------------------------- class TreeCtrlTestCase : public CppUnit::TestCase { public: TreeCtrlTestCase() { } virtual void setUp() wxOVERRIDE; virtual void tearDown() wxOVERRIDE; private: CPPUNIT_TEST_SUITE( TreeCtrlTestCase ); WXUISIM_TEST( ItemClick ); CPPUNIT_TEST( DeleteItem ); CPPUNIT_TEST( DeleteChildren ); CPPUNIT_TEST( DeleteAllItems ); WXUISIM_TEST( LabelEdit ); WXUISIM_TEST( KeyDown ); WXUISIM_TEST( CollapseExpandEvents ); WXUISIM_TEST( SelectionChange ); WXUISIM_TEST( Menu ); CPPUNIT_TEST( ItemData ); CPPUNIT_TEST( Iteration ); CPPUNIT_TEST( Parent ); CPPUNIT_TEST( CollapseExpand ); CPPUNIT_TEST( AssignImageList ); CPPUNIT_TEST( Focus ); CPPUNIT_TEST( Bold ); CPPUNIT_TEST( Visible ); CPPUNIT_TEST( Scroll ); CPPUNIT_TEST( Sort ); WXUISIM_TEST( KeyNavigation ); CPPUNIT_TEST( HasChildren ); CPPUNIT_TEST( SelectItemSingle ); CPPUNIT_TEST( PseudoTest_MultiSelect ); CPPUNIT_TEST( SelectItemMulti ); CPPUNIT_TEST( PseudoTest_SetHiddenRoot ); CPPUNIT_TEST( HasChildren ); CPPUNIT_TEST( GetCount ); CPPUNIT_TEST_SUITE_END(); void ItemClick(); void DeleteItem(); void DeleteChildren(); void DeleteAllItems(); void LabelEdit(); void KeyDown(); void CollapseExpandEvents(); void SelectionChange(); void Menu(); void ItemData(); void Iteration(); void Parent(); void CollapseExpand(); void AssignImageList(); void Focus(); void Bold(); void Visible(); void Scroll(); void Sort(); void KeyNavigation(); void HasChildren(); void GetCount(); void SelectItemSingle(); void SelectItemMulti(); void PseudoTest_MultiSelect() { ms_multiSelect = true; } void PseudoTest_SetHiddenRoot() { ms_hiddenRoot = true; } static bool ms_multiSelect; static bool ms_hiddenRoot; // the tree control itself wxTreeCtrl *m_tree; // and some of its items wxTreeItemId m_root, m_child1, m_child2, m_grandchild; wxDECLARE_NO_COPY_CLASS(TreeCtrlTestCase); }; // register in the unnamed registry so that these tests are run by default CPPUNIT_TEST_SUITE_REGISTRATION( TreeCtrlTestCase ); // also include in its own registry so that these tests can be run alone CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TreeCtrlTestCase, "TreeCtrlTestCase" ); // ---------------------------------------------------------------------------- // test initialization // ---------------------------------------------------------------------------- bool TreeCtrlTestCase::ms_multiSelect = false; bool TreeCtrlTestCase::ms_hiddenRoot = false; void TreeCtrlTestCase::setUp() { m_tree = new wxTreeCtrl(wxTheApp->GetTopWindow(), wxID_ANY, wxDefaultPosition, wxSize(400, 200), wxTR_DEFAULT_STYLE | wxTR_EDIT_LABELS); if ( ms_multiSelect ) m_tree->ToggleWindowStyle(wxTR_MULTIPLE); if ( ms_hiddenRoot ) m_tree->ToggleWindowStyle(wxTR_HIDE_ROOT); // actually set it m_root = m_tree->AddRoot("root"); m_child1 = m_tree->AppendItem(m_root, "child1"); m_child2 = m_tree->AppendItem(m_root, "child2"); m_grandchild = m_tree->AppendItem(m_child1, "grandchild"); m_tree->SetSize(400, 200); m_tree->ExpandAll(); m_tree->Refresh(); m_tree->Update(); } void TreeCtrlTestCase::tearDown() { delete m_tree; m_tree = NULL; m_root = m_child1 = m_child2 = m_grandchild = wxTreeItemId(); } // ---------------------------------------------------------------------------- // the tests themselves // ---------------------------------------------------------------------------- void TreeCtrlTestCase::HasChildren() { CPPUNIT_ASSERT( m_tree->HasChildren(m_root) ); CPPUNIT_ASSERT( m_tree->HasChildren(m_child1) ); CPPUNIT_ASSERT( !m_tree->HasChildren(m_child2) ); CPPUNIT_ASSERT( !m_tree->HasChildren(m_grandchild) ); } void TreeCtrlTestCase::GetCount() { CPPUNIT_ASSERT_EQUAL(3, m_tree->GetCount()); } void TreeCtrlTestCase::SelectItemSingle() { // this test should be only ran in single-selection control CPPUNIT_ASSERT( !m_tree->HasFlag(wxTR_MULTIPLE) ); // initially nothing is selected CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) ); // selecting an item should make it selected m_tree->SelectItem(m_child1); CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) ); // selecting it again shouldn't change anything m_tree->SelectItem(m_child1); CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) ); // selecting another item should switch the selection to it m_tree->SelectItem(m_child2); CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) ); CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) ); // selecting it again still shouldn't change anything m_tree->SelectItem(m_child2); CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) ); CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) ); // deselecting an item should remove the selection entirely m_tree->UnselectItem(m_child2); CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) ); CPPUNIT_ASSERT( !m_tree->IsSelected(m_child2) ); } void TreeCtrlTestCase::SelectItemMulti() { // this test should be only ran in multi-selection control CPPUNIT_ASSERT( m_tree->HasFlag(wxTR_MULTIPLE) ); // initially nothing is selected CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) ); // selecting an item should make it selected m_tree->SelectItem(m_child1); CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) ); // selecting it again shouldn't change anything m_tree->SelectItem(m_child1); CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) ); // selecting another item shouldn't deselect the previously selected one m_tree->SelectItem(m_child2); CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) ); CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) ); // selecting it again still shouldn't change anything m_tree->SelectItem(m_child2); CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) ); CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) ); // deselecting one of the items should leave the others selected m_tree->UnselectItem(m_child1); CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) ); CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) ); // collapsing a branch with selected items should still leave them selected m_tree->Expand(m_child1); m_tree->SelectItem(m_grandchild); CHECK( m_tree->IsSelected(m_grandchild) ); m_tree->Collapse(m_child1); CHECK( m_tree->IsSelected(m_grandchild) ); m_tree->Expand(m_child1); CHECK( m_tree->IsSelected(m_grandchild) ); } void TreeCtrlTestCase::ItemClick() { #if wxUSE_UIACTIONSIMULATOR EventCounter activated(m_tree, wxEVT_TREE_ITEM_ACTIVATED); EventCounter rclick(m_tree, wxEVT_TREE_ITEM_RIGHT_CLICK); wxUIActionSimulator sim; wxRect pos; m_tree->GetBoundingRect(m_child1, pos, true); // We move in slightly so we are not on the edge wxPoint point = m_tree->ClientToScreen(pos.GetPosition()) + wxPoint(4, 4); sim.MouseMove(point); wxYield(); sim.MouseDblClick(); wxYield(); sim.MouseClick(wxMOUSE_BTN_RIGHT); wxYield(); CPPUNIT_ASSERT_EQUAL(1, activated.GetCount()); CPPUNIT_ASSERT_EQUAL(1, rclick.GetCount()); #endif // wxUSE_UIACTIONSIMULATOR } void TreeCtrlTestCase::DeleteItem() { EventCounter deleteitem(m_tree, wxEVT_TREE_DELETE_ITEM); wxTreeItemId todelete = m_tree->AppendItem(m_root, "deleteme"); m_tree->AppendItem(todelete, "deleteme2"); m_tree->Delete(todelete); CPPUNIT_ASSERT_EQUAL(2, deleteitem.GetCount()); } void TreeCtrlTestCase::DeleteChildren() { EventCounter deletechildren(m_tree, wxEVT_TREE_DELETE_ITEM); m_tree->AppendItem(m_child1, "another grandchild"); m_tree->DeleteChildren(m_child1); CHECK( deletechildren.GetCount() == 2 ); } void TreeCtrlTestCase::DeleteAllItems() { EventCounter deleteall(m_tree, wxEVT_TREE_DELETE_ITEM); m_tree->DeleteAllItems(); CHECK( deleteall.GetCount() == 4 ); } #if wxUSE_UIACTIONSIMULATOR void TreeCtrlTestCase::LabelEdit() { EventCounter beginedit(m_tree, wxEVT_TREE_BEGIN_LABEL_EDIT); EventCounter endedit(m_tree, wxEVT_TREE_END_LABEL_EDIT); wxUIActionSimulator sim; m_tree->SetFocusedItem(m_tree->GetRootItem()); m_tree->EditLabel(m_tree->GetRootItem()); sim.Text("newroottext"); wxYield(); CPPUNIT_ASSERT_EQUAL(1, beginedit.GetCount()); sim.Char(WXK_RETURN); wxYield(); CPPUNIT_ASSERT_EQUAL(1, endedit.GetCount()); } void TreeCtrlTestCase::KeyDown() { EventCounter keydown(m_tree, wxEVT_TREE_KEY_DOWN); wxUIActionSimulator sim; m_tree->SetFocus(); sim.Text("aAbB"); wxYield(); CPPUNIT_ASSERT_EQUAL(6, keydown.GetCount()); } void TreeCtrlTestCase::CollapseExpandEvents() { #ifdef __WXGTK20__ // Works locally, but not when run on Travis CI. if ( IsAutomaticTest() ) return; #endif m_tree->CollapseAll(); EventCounter collapsed(m_tree, wxEVT_TREE_ITEM_COLLAPSED); EventCounter collapsing(m_tree, wxEVT_TREE_ITEM_COLLAPSING); EventCounter expanded(m_tree, wxEVT_TREE_ITEM_EXPANDED); EventCounter expanding(m_tree, wxEVT_TREE_ITEM_EXPANDING); wxUIActionSimulator sim; wxRect pos; m_tree->GetBoundingRect(m_root, pos, true); // We move in slightly so we are not on the edge wxPoint point = m_tree->ClientToScreen(pos.GetPosition()) + wxPoint(4, 4); sim.MouseMove(point); wxYield(); sim.MouseDblClick(); wxYield(); CPPUNIT_ASSERT_EQUAL(1, expanding.GetCount()); CPPUNIT_ASSERT_EQUAL(1, expanded.GetCount()); #ifdef __WXGTK__ // Don't even know the reason why, but GTK has to sleep // no less than 1200 for the test case to succeed. wxMilliSleep(1200); #endif sim.MouseDblClick(); wxYield(); CPPUNIT_ASSERT_EQUAL(1, collapsing.GetCount()); CPPUNIT_ASSERT_EQUAL(1, collapsed.GetCount()); } void TreeCtrlTestCase::SelectionChange() { m_tree->ExpandAll(); // This is currently needed to work around a problem under wxMSW: clicking // on an item in an unfocused control generates two selection change events // because of the SetFocus() call in TVN_SELCHANGED handler in wxMSW code. // This is, of course, wrong on its own, but fixing it without breaking // anything else is non-obvious, so for now at least work around this // problem in the test. m_tree->SetFocus(); EventCounter changed(m_tree, wxEVT_TREE_SEL_CHANGED); EventCounter changing(m_tree, wxEVT_TREE_SEL_CHANGING); wxUIActionSimulator sim; wxRect poschild1, poschild2; m_tree->GetBoundingRect(m_child1, poschild1, true); m_tree->GetBoundingRect(m_child2, poschild2, true); // We move in slightly so we are not on the edge wxPoint point1 = m_tree->ClientToScreen(poschild1.GetPosition()) + wxPoint(4, 4); wxPoint point2 = m_tree->ClientToScreen(poschild2.GetPosition()) + wxPoint(4, 4); sim.MouseMove(point1); wxYield(); sim.MouseClick(); wxYield(); CPPUNIT_ASSERT_EQUAL(1, changed.GetCount()); CPPUNIT_ASSERT_EQUAL(1, changing.GetCount()); sim.MouseMove(point2); wxYield(); sim.MouseClick(); wxYield(); CPPUNIT_ASSERT_EQUAL(2, changed.GetCount()); CPPUNIT_ASSERT_EQUAL(2, changing.GetCount()); } void TreeCtrlTestCase::Menu() { EventCounter menu(m_tree, wxEVT_TREE_ITEM_MENU); wxUIActionSimulator sim; wxRect pos; m_tree->GetBoundingRect(m_child1, pos, true); // We move in slightly so we are not on the edge wxPoint point = m_tree->ClientToScreen(pos.GetPosition()) + wxPoint(4, 4); sim.MouseMove(point); wxYield(); sim.MouseClick(wxMOUSE_BTN_RIGHT); wxYield(); CPPUNIT_ASSERT_EQUAL(1, menu.GetCount()); } #endif // wxUSE_UIACTIONSIMULATOR void TreeCtrlTestCase::ItemData() { wxTreeItemData* child1data = new wxTreeItemData(); wxTreeItemData* appenddata = new wxTreeItemData(); wxTreeItemData* insertdata = new wxTreeItemData(); m_tree->SetItemData(m_child1, child1data); CPPUNIT_ASSERT_EQUAL(child1data, m_tree->GetItemData(m_child1)); CPPUNIT_ASSERT_EQUAL(m_child1, child1data->GetId()); wxTreeItemId append = m_tree->AppendItem(m_root, "new", -1, -1, appenddata); CPPUNIT_ASSERT_EQUAL(appenddata, m_tree->GetItemData(append)); CPPUNIT_ASSERT_EQUAL(append, appenddata->GetId()); wxTreeItemId insert = m_tree->InsertItem(m_root, m_child1, "new", -1, -1, insertdata); CPPUNIT_ASSERT_EQUAL(insertdata, m_tree->GetItemData(insert)); CPPUNIT_ASSERT_EQUAL(insert, insertdata->GetId()); } void TreeCtrlTestCase::Iteration() { // Get first / next / last child wxTreeItemIdValue cookie; CPPUNIT_ASSERT_EQUAL(m_tree->GetFirstChild(m_root, cookie), m_child1); CPPUNIT_ASSERT_EQUAL(m_tree->GetNextChild(m_root, cookie), m_tree->GetLastChild(m_root)); CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetLastChild(m_root)); // Get next / previous sibling CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetNextSibling(m_child1)); CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetPrevSibling(m_child2)); } void TreeCtrlTestCase::Parent() { CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetRootItem()); CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetItemParent(m_child1)); CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetItemParent(m_child2)); CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetItemParent(m_grandchild)); } void TreeCtrlTestCase::CollapseExpand() { m_tree->ExpandAll(); CPPUNIT_ASSERT(m_tree->IsExpanded(m_root)); CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1)); m_tree->CollapseAll(); CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root)); CPPUNIT_ASSERT(!m_tree->IsExpanded(m_child1)); m_tree->ExpandAllChildren(m_root); CPPUNIT_ASSERT(m_tree->IsExpanded(m_root)); CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1)); m_tree->CollapseAllChildren(m_child1); CPPUNIT_ASSERT(!m_tree->IsExpanded(m_child1)); m_tree->Expand(m_child1); CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1)); m_tree->Collapse(m_root); CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root)); CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1)); m_tree->CollapseAndReset(m_root); CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root)); } void TreeCtrlTestCase::AssignImageList() { wxSize size(16, 16); wxImageList *imagelist = new wxImageList(size.x, size.y); imagelist->Add(wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, size)); wxImageList *statelist = new wxImageList(size.x, size.y); statelist->Add(wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, size)); m_tree->AssignImageList(imagelist); m_tree->AssignStateImageList(statelist); CPPUNIT_ASSERT_EQUAL(imagelist, m_tree->GetImageList()); CPPUNIT_ASSERT_EQUAL(statelist, m_tree->GetStateImageList()); } void TreeCtrlTestCase::Focus() { m_tree->SetFocusedItem(m_child1); CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetFocusedItem()); m_tree->ClearFocusedItem(); CPPUNIT_ASSERT(!m_tree->GetFocusedItem()); } void TreeCtrlTestCase::Bold() { CPPUNIT_ASSERT(!m_tree->IsBold(m_child1)); m_tree->SetItemBold(m_child1); CPPUNIT_ASSERT(m_tree->IsBold(m_child1)); m_tree->SetItemBold(m_child1, false); CPPUNIT_ASSERT(!m_tree->IsBold(m_child1)); } void TreeCtrlTestCase::Visible() { m_tree->CollapseAll(); CPPUNIT_ASSERT(m_tree->IsVisible(m_root)); CPPUNIT_ASSERT(!m_tree->IsVisible(m_child1)); m_tree->EnsureVisible(m_grandchild); CPPUNIT_ASSERT(m_tree->IsVisible(m_grandchild)); m_tree->ExpandAll(); CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetFirstVisibleItem()); CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetNextVisible(m_root)); CPPUNIT_ASSERT_EQUAL(m_grandchild, m_tree->GetNextVisible(m_child1)); CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetNextVisible(m_grandchild)); CPPUNIT_ASSERT(!m_tree->GetNextVisible(m_child2)); CPPUNIT_ASSERT(!m_tree->GetPrevVisible(m_root)); } void TreeCtrlTestCase::Scroll() { // This trivial test just checks that calling ScrollTo() with the root item // doesn't crash any longer, as it used to do when the root item was hidden. m_tree->ScrollTo(m_root); } void TreeCtrlTestCase::Sort() { wxTreeItemId zitem = m_tree->AppendItem(m_root, "zzzz"); wxTreeItemId aitem = m_tree->AppendItem(m_root, "aaaa"); m_tree->SortChildren(m_root); wxTreeItemIdValue cookie; CPPUNIT_ASSERT_EQUAL(aitem, m_tree->GetFirstChild(m_root, cookie)); CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetNextChild(m_root, cookie)); CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetNextChild(m_root, cookie)); CPPUNIT_ASSERT_EQUAL(zitem, m_tree->GetNextChild(m_root, cookie)); } void TreeCtrlTestCase::KeyNavigation() { #if wxUSE_UIACTIONSIMULATOR wxUIActionSimulator sim; m_tree->CollapseAll(); m_tree->SelectItem(m_root); wxYield(); m_tree->SetFocus(); sim.Char(WXK_RIGHT); wxYield(); CPPUNIT_ASSERT(m_tree->IsExpanded(m_root)); #ifdef wxHAS_GENERIC_TREECTRL sim.Char('-'); #else sim.Char(WXK_LEFT); #endif wxYield(); CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root)); wxYield(); sim.Char(WXK_RIGHT); sim.Char(WXK_DOWN); wxYield(); CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetSelection()); sim.Char(WXK_DOWN); wxYield(); CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetSelection()); #endif } #endif //wxUSE_TREECTRL