Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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)
Example #6
0
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)
Example #7
0
    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()
Example #8
0
    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()
Example #9
0
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())
Example #10
0
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
Example #11
0
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"
Example #12
0
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()
Example #13
0
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()
Example #15
0
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
Example #16
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 == ""
Example #18
0
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
Example #19
0
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
Example #20
0
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 == ""
Example #22
0
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)
Example #23
0
    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()
Example #24
0
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() != ""
Example #28
0
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
Example #29
0
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
Example #30
0
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