# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Timeline is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Timeline. If not, see <http://www.gnu.org/licenses/>.
from unittest.mock import Mock
import humblewx
from timelinelib.canvas.drawing.viewproperties import ViewProperties
from timelinelib.dataimport.tutorial import create_in_memory_gregorian_tutorial_db
from timelinelib.test.cases.unit import UnitTestCase
from timelinelib.test.utils import a_category_with
from timelinelib.wxgui.components.categorytree import CategoriesFacade
from timelinelib.wxgui.components.categorytree import CustomCategoryTreeModel
from timelinelib.wxgui.framework import Dialog
[docs]class describe_custom_category_tree_component_test(UnitTestCase):
#def test_it_shows_in_dialog(self):
# self.show_dialog(TestDialog, create_in_memory_gregorian_tutorial_db(), ViewProperties())
pass
[docs]class TestDialog(Dialog):
"""
<BoxSizerVertical>
<CustomCategoryTree
name="tree"
width="300"
height="300"
/>
</BoxSizerVertical>
"""
[docs] def __init__(self, db, view_properties):
Dialog.__init__(self, humblewx.Controller, None, {
})
self.tree.set_timeline_view(db, view_properties)
@property
def config(self):
return Config()
[docs]class Config:
@property
def use_sidebar_text_coloring(self):
return False
@property
def debug_enabled(self):
return False
[docs]class Base(UnitTestCase):
[docs] def setUp(self):
self.categories = []
self.visible_categories = []
self.actually_visible_categories = []
self.categories_facade = Mock(CategoriesFacade)
self.categories_facade.get_all.return_value = self.categories
self.categories_facade.is_visible.side_effect = self._category_visible
self.categories_facade.is_event_with_category_visible.side_effect = self._event_with_category_visible
self.model = CustomCategoryTreeModel()
self.id_counter = 0
[docs] def new_id(self):
self.id_counter += 1
return self.id_counter
def _category_visible(self, category):
return category in self.visible_categories
def _event_with_category_visible(self, category):
return category in self.actually_visible_categories
[docs] def add_category(self, name, color=(0, 0, 0), visible=True, actually_visible=True, parent=None):
category = a_category_with(name=name, color=color, parent=parent)
category.set_id(self.new_id())
if visible:
self.visible_categories.append(category)
if actually_visible:
self.actually_visible_categories.append(category)
self.categories.append(category)
return category
[docs] def assert_model_has_itmes_matching(self, expected_entries):
self.assertEqual(len(self.model.get_items()), len(expected_entries))
for i in range(len(self.model.get_items())):
for key in expected_entries[i]:
self.assertEqual(self.model.get_items()[i][key],
expected_entries[i][key])
[docs] def assert_model_has_item_names(self, expected_names):
self.assertEqual([x["name"] for x in self.model.get_items()], expected_names)
[docs]class setting_categories(Base):
[docs] def test_has_no_items_when_no_timeline_view_set(self):
self.assert_model_has_itmes_matching([])
[docs] def test_has_no_items_when_no_categories_available(self):
self.model.set_categories(self.categories_facade)
self.assert_model_has_itmes_matching([])
[docs] def test_has_items_for_each_category(self):
self.add_category("Play")
self.add_category("Work")
self.model.set_categories(self.categories_facade)
self.assert_model_has_item_names(["Play", "Work"])
[docs] def test_can_set_view_multiple_times_without_items_duplicating(self):
self.add_category("Work")
self.model.set_categories(self.categories_facade)
self.model.set_categories(self.categories_facade)
self.assertEqual(len(self.model.get_items()), 1)
[docs]class item_properties(Base):
[docs] def test_has_items_for_categories(self):
play_category = self.add_category(
"Play", (255, 0, 100), visible=False, actually_visible=True)
work_category = self.add_category(
"Work", (88, 55, 22), visible=True, actually_visible=False)
self.model.set_categories(self.categories_facade)
self.assert_model_has_itmes_matching([
{
"id": play_category.get_id(),
"name": "Play",
"visible": False,
"actually_visible": True,
"color": (255, 0, 100),
"category": play_category,
},
{
"id": work_category.get_id(),
"name": "Work",
"visible": True,
"actually_visible": False,
"color": (88, 55, 22),
"category": work_category,
},
])
[docs] def test_has_child_attribute(self):
play_category = self.add_category("Play")
work_category = self.add_category("Work", parent=play_category)
self.model.set_categories(self.categories_facade)
self.assert_model_has_itmes_matching([
{
"name": "Play",
"has_children": True,
},
{
"name": "Work",
"has_children": False,
},
])
[docs]class bounding_box(Base):
[docs] def test_has_indented_bounding_box_for_child_categories(self):
self.model.INDENT_PX = 10
work_category = self.add_category("Work")
self.add_category("Reading", parent=work_category)
self.model.set_view_size(200, 900)
self.model.set_categories(self.categories_facade)
self.assert_model_has_itmes_matching([
{
"name": "Work",
"x": 0,
"width": 200,
},
{
"name": "Reading",
"x": 10,
"width": 190,
},
])
[docs]class sorting(Base):
[docs] def test_sorts_categories_at_same_level(self):
self.add_category("Work")
self.add_category("Reading")
self.model.set_categories(self.categories_facade)
self.assert_model_has_item_names(["Reading", "Work"])
[docs]class hit_test(Base):
[docs] def test_can_get_category(self):
reading = self.add_category("Reading")
work = self.add_category("Work")
self.model.set_categories(self.categories_facade)
self.assertEqual(self.model.hit(0, 0).get_category(), reading)
self.assertEqual(self.model.hit(0, 25).get_category(), work)
self.assertEqual(self.model.hit(0, 45).get_category(), None)
[docs] def test_can_check_if_hit_arrow(self):
reading = self.add_category("Reading")
self.model.set_categories(self.categories_facade)
self.assertEqual(self.model.hit(5, 10).is_on_arrow(), True)
self.assertEqual(self.model.hit(0, 25).is_on_arrow(), False)
[docs] def test_can_check_if_hit_checkbox(self):
reading = self.add_category("Reading")
self.model.set_categories(self.categories_facade)
self.assertEqual(self.model.hit(25, 10).is_on_checkbox(), True)
self.assertEqual(self.model.hit(0, 25).is_on_checkbox(), False)
[docs] def setUp(self):
Base.setUp(self)
self.model.ITEM_HEIGHT_PX = 20
[docs]class expandedness(Base):
[docs] def test_can_toggle(self):
reading = self.add_category("Reading")
work = self.add_category("Work")
self.model.set_categories(self.categories_facade)
self.assert_model_has_itmes_matching([
{"name": "Reading", "expanded": True, },
{"name": "Work", "expanded": True, },
])
self.model.toggle_expandedness(work)
self.assert_model_has_itmes_matching([
{"name": "Reading", "expanded": True, },
{"name": "Work", "expanded": False, },
])
self.model.toggle_expandedness(work)
self.assert_model_has_itmes_matching([
{"name": "Reading", "expanded": True, },
{"name": "Work", "expanded": True, },
])
[docs] def test_hides_subtrees_if_parent_not_expanded(self):
work_category = self.add_category("Work")
self.add_category("Reading", parent=work_category)
self.model.set_categories(self.categories_facade)
self.assert_model_has_item_names(["Work", "Reading"])
self.model.toggle_expandedness(work_category)
self.assert_model_has_item_names(["Work"])