def test_has_children_handles_plan_index(): """ When no project is set, hasChildren should return False """ # Given model = TreeModel() project = ResearchProject("") project.add_plan().add_task() model.set_project(project) # Then assert model.hasChildren(model.index(0, 0, model.plans_index)) is True
def test_flags_not_editable_for_ancestor_column(): """ The ancestor column should not be editable """ model = TreeModel() project = ResearchProject("") project.add_plan().add_task() model.set_project(project) # When plan_index = model.index(0, TreeModelCols.ANCESTOR, model.plans_index) task_index = model.index(0, TreeModelCols.ANCESTOR, plan_index) # Then assert model.flags(plan_index) & Qt.ItemIsEditable != Qt.ItemIsEditable assert model.flags(task_index) & Qt.ItemIsEditable != Qt.ItemIsEditable
def test_pending_updates_are_cleared(): """ If there are any previous pending changes, they are cleared before updates are calculated """ # Given tree_model = TreeModel() tree_model.set_project(ResearchProject("")) individuals_model = IndividualsModel([]) sources_model = SourcesModel([]) context = DataContext( data_model=tree_model, individuals_model=individuals_model, sources_model=sources_model, ) updater = LinkUpdater(context) updater.source_updates = ["Foo", "Bar"] updater.ancestor_fixes = ["Baz", "Fiz"] # When updater.calculate_updates() # Then assert updater.has_pending_updates() is False
def test_delete_does_nothing_on_invalid_index(qtbot): """ Delete removes task from underlying data structure """ # Given model = TreeModel() project = ResearchProject("") project.add_plan().add_task() model.set_project(project) # When with qtbot.assertNotEmitted(model.rowsAboutToBeRemoved): with qtbot.assertNotEmitted(model.rowsRemoved): model.delete_node(QModelIndex()) # Then assert len(project.plans) == 1 assert len(project.plans[0].tasks) == 1
def fixture_link_updater(): """ Fixture to create an updater with uncommitted updates """ tree_model = TreeModel() individuals_model = IndividualsModel([]) sources_model = SourcesModel([]) old_value = "Altered Ancestor" new_value = "Foo" project = ResearchProject("") plan_altered = ResearchPlan() plan_altered.ancestor = old_value plan_altered.ancestor_link = "I001" project.plans.append(plan_altered) tree_model.set_project(project) context = DataContext( data_model=tree_model, individuals_model=individuals_model, sources_model=sources_model, ) updater = LinkUpdater(context) plan_index = tree_model.index(0, TreeModelCols.TEXT, QModelIndex()) updater.ancestor_updates = [{"index": plan_index, "value": new_value}] return (updater, old_value, new_value, tree_model, plan_index)
def test_show_classmethod(monkeypatch): """ Check the function does what it says """ # Given monkeypatch.setattr(ProjectOverviewDialog, "exec_", lambda _: None) # When ProjectOverviewDialog.show(DataContext(), ResearchProject("Foobar"), None)
def create_new_project(self): """ Creates a new Research Project """ if self.needs_saving: button = self.project_discard.exec_() if button == QMessageBox.Cancel: return (file_name, _) = QFileDialog.getSaveFileName(self.parent(), "Create a project", ".", "Grant Project (*.gra)") if file_name == "": return self.project = ResearchProject(file_name) self.save_project() self.project_changed.emit()
def open_project(self): """ Opens an existing project """ if self.needs_saving: button = self.project_discard.exec_() if button == QMessageBox.Cancel: return (file_name, _) = QFileDialog.getOpenFileName(self.parent(), "Open a project", ".", "Grant Project (*.gra)") if file_name == "": return self.project = ResearchProject(file_name) with open(self.project.filename) as file: self.project.from_py(yaml.safe_load(file)) self.project_changed.emit()
def test_setting_selected_item_on_detail_screen_checks_for_mapper(qtbot): """ Detail screens may not have a mapper, so check before using it """ # Given screen = DetailScreen(None) screen.project = ResearchProject("") qtbot.addWidget(screen) # When screen.set_selected_item(QModelIndex())
def test_task_links_are_checked(): """ Check the following: * Unchanged links are respected * Broken links are identified * Updated links are identified """ # Given project = ResearchProject("") individuals = [] sources = [] plan = ResearchPlan() source_linked = Source("S123", "Linked", "Author", "Pub", "abbr") sources.append(source_linked) task_linked = ResearchTask() task_linked.source = source_linked.autocomplete_name() task_linked.source_link = source_linked.pointer plan.tasks.append(task_linked) task_broken = ResearchTask() task_broken.source = "Broken Source" task_broken.source_link = "FooBar" plan.tasks.append(task_broken) source_altered = Source("S987", "Altered", "Author", "Pub", "abbr") sources.append(source_altered) task_altered = ResearchTask() task_altered.source = "Altered Source" task_altered.source_link = source_altered.pointer plan.tasks.append(task_altered) project.plans.append(plan) tree_model = TreeModel() tree_model.set_project(project) individuals_model = IndividualsModel(individuals) sources_model = SourcesModel(sources) context = DataContext( data_model=tree_model, individuals_model=individuals_model, sources_model=sources_model, ) updater = LinkUpdater(context) # When updater.calculate_updates() # Then assert updater.has_pending_updates() is True assert len(updater.ancestor_updates) == 0 assert len(updater.source_updates) == 1
def test_dialog_builds(qtbot): """ a """ # Given dialog = ProjectOverviewDialog(DataContext(), ResearchProject("Foobar"), None) qtbot.add_widget(dialog) # When # Then assert dialog.filename_label.text() == "Foobar"
def test_setting_selected_item_on_detail_screen_updates_mapper(qtbot): """ Mapper should be set for Detail screen """ # Given screen = DetailScreen(None) screen.project = ResearchProject("") screen.mapper = mock.MagicMock() qtbot.addWidget(screen) # When screen.set_selected_item(QModelIndex()) screen.mapper.setRootIndex.assert_called()
def test_set_project_clears_existing_nodes(): """ Setting valid project should clear existing nodes """ # Given model = TreeModel() project = ResearchProject("") # When model.set_project(project) model.set_project(project) # Then assert len(model.plans_node.children) == 0
def test_save_emits_signal(qtbot, tmpdir): """ When saving, the signal is raised """ # Given filename = tmpdir.join("test_save_resets_need_saving.txt") manager = ProjectFileManager() qtbot.add_widget(manager) project = ResearchProject(str(filename)) manager.project = project # When with qtbot.waitSignals([manager.project_saved]): manager.save_project()
def test_plan_links_are_checked(): """ Check the following: * Unchanged links are respected * Broken links are identified * Updated links are identified """ # Given project = ResearchProject("") individuals = [] sources = [] indi_linked = Individual("I1234", "Link", "Indi", 1000, 2000) individuals.append(indi_linked) plan_linked = ResearchPlan() plan_linked.ancestor = indi_linked.autocomplete_name() plan_linked.ancestor_link = indi_linked.pointer project.plans.append(plan_linked) plan_broken = ResearchPlan() plan_broken.ancestor = "Broken Ancestor 1234/5678" plan_broken.ancestor_link = "FooBar" project.plans.append(plan_broken) indi_altered = Individual("I9876", "Altered", "Indi", 1000, 2000) individuals.append(indi_altered) plan_altered = ResearchPlan() plan_altered.ancestor = "Altered Ancestor 1000/2000" plan_altered.ancestor_link = indi_altered.pointer project.plans.append(plan_altered) tree_model = TreeModel() tree_model.set_project(project) individuals_model = IndividualsModel(individuals) sources_model = SourcesModel(sources) context = DataContext( data_model=tree_model, individuals_model=individuals_model, sources_model=sources_model, ) updater = LinkUpdater(context) # When updater.calculate_updates() # Then assert updater.has_pending_updates() is True assert len(updater.ancestor_updates) == 1 assert len(updater.source_updates) == 0
def test_update_project_updates_screens(qtbot): """ When caling update_project, this is passed to the screens """ # Given screen = MainScreen(None, DataContext()) qtbot.add_widget(screen) project = ResearchProject("") assert screen.screens["blank"].project is None # When screen.set_project(project) # Then assert screen.screens["blank"].project == project
def test_unlink_gedcom_does_nothing_if_no_gedcom_link_set(qtbot): """ If there is no gedcom link, nothing should happen """ # Given manager = ProjectFileManager() manager.project = ResearchProject("") # monkeypatch.delattr(manager.gedcom_discard, "exec_") # when with qtbot.assertNotEmitted(manager.project_changed): manager.unlink_gedcom_file() # Then assert manager.project.gedcom == ""
def test_update_project_sets_project(qtbot): """ update_project() slot sets the screen's project reference """ # Given screen = BaseScreen(None) project = ResearchProject("") qtbot.addWidget(screen) # When screen.update_project(project) # Then assert screen.project is not None assert screen.project == project
def test_add_creates_plan(): """ Add should create a new plan in the underlying data structure """ # Given model = TreeModel() project = ResearchProject("") model.set_project(project) # When model.add_node(model.plans_index) # Then assert len(project.plans) == 1
def test_flags_set_for_line_items(): """ Check flags are set correctly for plans and tasks """ # Given model = TreeModel() project = ResearchProject("") project.add_plan().add_task() model.set_project(project) # When plan_index = model.index(0, 0, model.plans_index) task_index = model.index(0, 0, plan_index) # Then plan_flags = int(model.flags(plan_index)) task_flags = int(model.flags(task_index)) assert plan_flags & Qt.ItemIsSelectable == Qt.ItemIsSelectable assert plan_flags & Qt.ItemIsEditable == Qt.ItemIsEditable assert plan_flags & Qt.ItemIsEnabled == Qt.ItemIsEnabled assert task_flags & Qt.ItemIsSelectable == Qt.ItemIsSelectable assert task_flags & Qt.ItemIsEditable == Qt.ItemIsEditable assert task_flags & Qt.ItemIsEnabled == Qt.ItemIsEnabled
def test_link_gedcom_does_nothing_on_cancel(monkeypatch, qtbot): """ When the fileopen dialog is cancelled, the gedcom path is not changed """ # Given manager = ProjectFileManager() manager.project = ResearchProject("") monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda _, __, ___, ____: ("", False)) # When with qtbot.assertNotEmitted(manager.project_changed): manager.link_gedcom_file() # Then assert manager.project.gedcom == ""
def test_delete_calls_signals(qtbot): """ The start and end row removal signals should be emitted """ # Given model = TreeModel() project = ResearchProject("") plan = ResearchPlan() project.plans.append(plan) model.set_project(project) plan_index = model.index(0, 0, model.plans_index) # When with qtbot.waitSignals([model.rowsAboutToBeRemoved, model.rowsRemoved]): model.delete_node(plan_index)
def __init__(self): super(MainWindow, self).__init__() self.data_context = DataContext() self.main_screen = None self.project_manager = ProjectFileManager(self) self.gedcom_manager = GedcomManager(self.data_context, self) self.setup_window() self.setup_window_title() self.setup_menubar() if os.getenv("GRANT_TEST", "") != "": self.project_manager.project = ResearchProject("test_data") self.project_manager.project.from_py(yaml.safe_load(TEST_DATA)) self.project_manager.project_changed.emit()
def test_setdata_returns_false_on_invalid_index(): """ When setting data, false is returned for invalid index """ # Given model = TreeModel() project = ResearchProject("") plan = ResearchPlan() project.plans.append(plan) model.set_project(project) # When retval = model.setData(QModelIndex(), "Foo") assert retval is False
def test_save_resets_need_saving(qtbot, tmpdir): """ When saving, the needs_saving flag is reset """ # Given filename = tmpdir.join("test_save_resets_need_saving.txt") manager = ProjectFileManager() qtbot.add_widget(manager) project = ResearchProject(str(filename)) manager.project = project manager.needs_saving = True # When manager.save_project() # Then assert manager.needs_saving is False
def test_unlink_discard_cancel_makes_no_change(monkeypatch, qtbot): """ When a link exists and the confirmation dialog cancels, nothing should happen """ # Given manager = ProjectFileManager() manager.project = ResearchProject("") manager.project.gedcom = "Foo" monkeypatch.setattr(manager.gedcom_discard, "exec_", lambda: QMessageBox.Cancel) # when with qtbot.assertNotEmitted(manager.project_changed): manager.unlink_gedcom_file() # Then assert manager.project.gedcom == "Foo"
def test_save_writes_project(qtbot, tmpdir): """ When saving, the file is written""" # Given filename = tmpdir.join("test_save_resets_need_saving.txt") manager = ProjectFileManager() qtbot.add_widget(manager) project = ResearchProject(str(filename)) manager.project = project # When with qtbot.waitSignals([manager.project_saved]): manager.save_project() # Then assert filename.read() != ""
def test_setdata_returns_false_on_invalid_column(): """ When setting data, false is returned for invalid column """ # Given model = TreeModel() project = ResearchProject("") plan = ResearchPlan() project.plans.append(plan) model.set_project(project) plan_index = model.index(0, model.columnCount(None) + 1, model.plans_index) # When retval = model.setData(plan_index, "Foo") assert retval is False
def test_data_returns_none_for_invalid_index(): """ When getting data, nothing is returned for invalid index """ # Given model = TreeModel() project = ResearchProject("") plan = ResearchPlan() project.plans.append(plan) model.set_project(project) # When retval = model.data(QModelIndex(), Qt.DisplayRole) # Then assert retval is None
def test_index_returns_index_for_valid_row(): """ The start and end row removal signals should be emitted """ # Given model = TreeModel() project = ResearchProject("") plan = ResearchPlan() project.plans.append(plan) model.set_project(project) # When plan_index = model.index(0, 0, model.plans_index) # Then assert plan_index.isValid() is True