Exemplo n.º 1
0
    def test_thawing_a_parent_with_completed_children_works(
            self, repo: FakeRepository,
            insert_parent_task: Tuple[RecurrentTask, Task]) -> None:
        """
        Given: A parent with completed children
        When: Thawing the parent
        Then: The parent is thawed and the next children is breeded
        """
        parent_task, child_task = insert_parent_task
        services._close_task(repo, child_task, TaskState.DONE)
        repo.commit()
        selector = TaskSelector(task_ids=[parent_task.id_],
                                model=RecurrentTask)
        services.freeze_tasks(repo, selector)

        services.thaw_tasks(repo, selector)  # act

        parent_task = repo.get(parent_task.id_, [RecurrentTask])
        assert parent_task.state == TaskState.BACKLOG
        children_tasks = repo.search(
            {
                "parent_id": parent_task.id_,
                "active": True
            }, [Task])
        assert len(children_tasks) == 1
Exemplo n.º 2
0
    def test_modify_child_task_parent_notifies_orphan_if_no_parent(
        self,
        repo: FakeRepository,
        task: Task,
        caplog: LogCaptureFixture,
        faker: Faker,
    ) -> None:
        """
        Given: A task without parent
        When: modifying the task with modify_parent = True
        Then: A warning is shown that the task has no parent.
        """
        selector = TaskSelector(task_ids=[task.id_])
        description = faker.sentence()
        change = TaskChanges(task_attributes={"description": description})

        services.modify_tasks(repo, selector, change,
                              modify_parent=True)  # act

        modified_task = repo.get(task.id_, [Task])
        assert modified_task.description == description
        assert (
            "pydo.services",
            logging.WARNING,
            f"Task {task.id_} doesn't have a parent task.",
        ) in caplog.record_tuples
Exemplo n.º 3
0
    def test_close_task_sets_state_and_close_date(
        self,
        action: Callable[[FakeRepository, TaskSelector], None],
        state: str,
        repo: FakeRepository,
        task: Task,
        freezer: FrozenDateTimeFactory,  # noqa: W0613
        caplog: LogCaptureFixture,
    ) -> None:
        """
        Given: An existent task.
        When: using the do_tasks or rm_tasks.
        Then: The task is closed with the respective state and the closed date is set.
        """
        selector = TaskSelector(task_ids=[task.id_])
        now = datetime.now()

        action(repo, selector)  # act

        task = repo.get(task.id_, [Task])
        assert task.closed == now
        assert task.modified == now
        assert task.state == state
        assert (
            "pydo.services",
            logging.INFO,
            f"Closing task {task.id_}: {task.description} with state {state}",
        ) in caplog.record_tuples
Exemplo n.º 4
0
    def test_close_task_doesnt_close_already_closed_tasks(
        self,
        action: Callable[[FakeRepository, TaskSelector], None],
        state: str,
        repo: FakeRepository,
        tasks: List[Task],
        freezer: FrozenDateTimeFactory,  # noqa: W0613
        caplog: LogCaptureFixture,
    ) -> None:
        """
        Given: An existent closed task.
        When: using the do_tasks or rm_tasks.
        Then: Only the open task is closed.
        """
        closed_task = tasks[0]
        services._close_task(repo, closed_task, TaskState.DONE)
        caplog.clear()
        selector = TaskSelector(task_ids=[closed_task.id_, tasks[1].id_])

        action(repo, selector)  # act

        task = repo.get(tasks[1].id_, [Task])
        assert task.state == state
        assert (
            "pydo.services",
            logging.INFO,
            f"Closing task {closed_task.id_}: {closed_task.description} "
            f"with state {state}",
        ) not in caplog.record_tuples
Exemplo n.º 5
0
    def test_modify_task_modifies_task_attributes(
        self,
        repo: FakeRepository,
        faker: Faker,
        task: Task,
        caplog: LogCaptureFixture,
    ) -> None:
        """
        Given: An existent task.
        When: Using modify_task to modify the description.
        Then: The description is modified.
        """
        now = datetime.now()
        description = faker.sentence()
        selector = TaskSelector(task_ids=[task.id_])
        change = TaskChanges(task_attributes={"description": description}, )

        services.modify_tasks(repo, selector, change)  # act

        modified_task = repo.get(task.id_, [Task])
        assert modified_task.description == description
        assert (modified_task.modified - now).total_seconds() < 2
        assert (
            "pydo.services",
            logging.INFO,
            f"Modified task {task.id_}.",
        ) in caplog.record_tuples
Exemplo n.º 6
0
    def test_close_orphan_child_task_with_delete_parent_logs_the_error(
        self,
        action: Callable[..., None],
        state: str,
        repo: FakeRepository,
        task: Task,
        freezer: FrozenDateTimeFactory,  # noqa: W0613
        caplog: LogCaptureFixture,
    ) -> None:
        """
        Given: A repository with a task without a parent.
        When: Using the do_tasks or rm_tasks on the task
            with the delete_parent flag.
        Then: The task is closed, and the warning is raised.
        """
        now = datetime.now()
        selector = TaskSelector(task_ids=[task.id_])

        action(repo, selector, delete_parent=True)  # act

        assert task.state == state
        assert task.closed == now
        assert (
            "pydo.services",
            logging.INFO,
            f"Task {task.id_} doesn't have a parent",
        ) in caplog.record_tuples
Exemplo n.º 7
0
    def test_close_child_task_with_delete_parent_true_also_do_parent(
            self,
            action: Callable[..., None],
            state: str,
            repo: FakeRepository,
            parent_and_child_tasks: Tuple[RecurrentTask, Task],
            freezer: FrozenDateTimeFactory,  # noqa: W0613
    ) -> None:
        """
        Given: A repository with a parent and a child task.
        When: Using the do_tasks or rm_tasks on the child_id
            with the delete_parent flag.
        Then: The child and parent are closed.
        """
        now = datetime.now()
        parent_task, child_task = parent_and_child_tasks
        selector = TaskSelector(task_ids=[child_task.id_])

        action(repo, selector, delete_parent=True)  # act

        parent_task = repo.get(parent_task.id_, [RecurrentTask])
        assert parent_task.state == state
        assert parent_task.closed == now
        assert child_task.state == state
        assert child_task.closed == now
Exemplo n.º 8
0
    def test_freeze_parent_task_sets_state(
        self,
        repo: FakeRepository,
        parent_and_child_tasks: Tuple[RecurrentTask, Task],
        caplog: LogCaptureFixture,
    ) -> None:
        """
        Given: A recurrent parent and child tasks.
        When: using the freeze_tasks on the child task
        Then: The parent's state becomes frozen, and the last child is deleted from
            the repository.
        """
        parent_task, child_task = parent_and_child_tasks
        selector = TaskSelector(task_ids=[parent_task.id_],
                                model=RecurrentTask)

        services.freeze_tasks(repo, selector)  # act

        with pytest.raises(EntityNotFoundError):
            repo.get(child_task.id_, [Task])
        parent_task = repo.get(parent_task.id_, [RecurrentTask])
        assert parent_task.active is False
        assert parent_task.state == TaskState.FROZEN
        assert (
            "pydo.services",
            logging.INFO,
            f"Frozen recurrent task {parent_task.id_}: {parent_task.description} and "
            f"deleted it's last child {child_task.id_}",
        ) in caplog.record_tuples
Exemplo n.º 9
0
    def test_thawing_returns_error_if_no_tasks_to_thaw(
            self, repo: FakeRepository) -> None:
        """
        Given: An empty repository
        When: Thawing a list of tasks that don't exist
        Then: An error is shown
        """
        selector = TaskSelector(task_attributes={"state": "todo"})

        with pytest.raises(
                EntityNotFoundError,
                match="No frozen tasks were found with that criteria"):
            services.thaw_tasks(repo, selector)  # act
Exemplo n.º 10
0
def test_task_selector_doesnt_return_tasks_that_dont_match_filter(
        repo: Repository, task: Task) -> None:
    """
    Given: A task in the repository
    When: using a task selector with that id and a filter that doesn't match the task
    Then: No task is returned
    """
    selector = TaskSelector(task_ids=[task.id_],
                            task_filter={"body": "not there"})

    result = services._tasks_from_selector(repo, selector)

    assert len(result) == 0
Exemplo n.º 11
0
    def test_modify_task_adds_tags(self, repo: FakeRepository, task: Task,
                                   faker: Faker) -> None:
        """
        Given: A task without tags
        When: modifying it to add a tag
        Then: the tags are added
        """
        selector = TaskSelector(task_ids=[task.id_])
        tag = faker.word()
        change = TaskChanges(tags_to_add=[tag])

        services.modify_tasks(repo, selector, change)  # act

        modified_task = repo.get(task.id_, [Task])
        assert modified_task.tags == [tag]
Exemplo n.º 12
0
    def test_close_child_task_generates_next_children(
        self,
        action: Callable[[FakeRepository, TaskSelector], None],
        state: str,
        repo: FakeRepository,
        parent_and_child_tasks: Tuple[RecurrentTask, Task],
        caplog: LogCaptureFixture,
    ) -> None:
        """
        Given: A repository with a parent and a child task.
        When: Using the do_tasks or rm_tasks on the child_id.
        Then: The child is closed, the new child is created, and the parent
            is left open.
        """
        now = datetime.now()
        parent_task, child_task = parent_and_child_tasks
        selector = TaskSelector(task_ids=[child_task.id_])

        action(repo, selector)  # act

        parent_task = repo.get(parent_task.id_, [RecurrentTask])
        new_child = repo.search({
            "parent_id": parent_task.id_,
            "active": True
        }, [Task])[-1]
        assert new_child is not None
        assert new_child > child_task
        assert parent_task.state == "backlog"
        assert child_task.state == state
        assert child_task.closed is not None
        assert (child_task.closed - now).total_seconds() < 2
        assert new_child.state == "backlog"
        assert (new_child.created - now).total_seconds() < 2
        assert new_child.due is not None
        assert new_child.due >= parent_task.due
        assert (
            "pydo.services",
            logging.INFO,
            f"Closing child task {child_task.id_}: {child_task.description} with state"
            f" {state}",
        ) in caplog.record_tuples
        assert (
            "pydo.services",
            logging.INFO,
            f"Added child task {new_child.id_}: {new_child.description}",
        ) in caplog.record_tuples
Exemplo n.º 13
0
    def test_modify_doesnt_change_task_if_change_changes_nothing(
            self, repo: FakeRepository, task: Task, caplog: LogCaptureFixture,
            faker: Faker) -> None:
        """
        Given: A task
        When: modifying it's description to the same value
        Then: The modified task log message is not shown
        """
        selector = TaskSelector(task_ids=[task.id_])
        change = TaskChanges(task_attributes={"description": task.description})

        services.modify_tasks(repo, selector, change)  # act

        assert (
            "pydo.services",
            logging.INFO,
            f"Modified task {task.id_}.",
        ) not in caplog.record_tuples
Exemplo n.º 14
0
    def test_modify_raises_error_if_task_not_found(
            self, repo: FakeRepository, faker: Faker, task: Task,
            caplog: LogCaptureFixture) -> None:
        """
        Given: An inexistent task
        When: Using modify_tasks on an that task
        Then: An error is raised
        """
        selector = TaskSelector(task_ids=[9999999])
        change = TaskChanges(task_attributes={"description":
                                              faker.sentence()}, )

        with pytest.raises(
                EntityNotFoundError,
                match=
                "There are no entities of type Task in the repository with id",
        ):
            services.modify_tasks(repo, selector, change)  # act
Exemplo n.º 15
0
    def test_modify_task_removes_tags(self, repo: FakeRepository, task: Task,
                                      faker: Faker) -> None:
        """
        Given: A task with a tag
        When: modifying it to remove the tag
        Then: the tags are removed, but the rest of the properties are kept.
        """
        tag = faker.word()
        selector = TaskSelector(task_ids=[task.id_])
        change = TaskChanges(tags_to_add=[tag])
        services.modify_tasks(repo, selector, change)
        change = TaskChanges(tags_to_remove=[tag])

        services.modify_tasks(repo, selector, change)  # act

        modified_task = repo.get(task.id_, [Task])
        assert modified_task.tags == []
        assert modified_task.description == task.description
Exemplo n.º 16
0
    def test_modify_task_warns_if_task_doesnt_have_any_tag(
            self, repo: FakeRepository, task: Task, caplog: LogCaptureFixture,
            faker: Faker) -> None:
        """
        Given: A task without a tag
        When: modifying it to remove the tag
        Then: A warning is shown that the task doesn't have any tag to remove
        """
        selector = TaskSelector(task_ids=[task.id_])
        tag = faker.word()
        change = TaskChanges(tags_to_remove=[tag])

        services.modify_tasks(repo, selector, change)  # act

        assert (
            "pydo.services",
            logging.WARNING,
            f"Task {task.id_} doesn't have the tag {tag} assigned.",
        ) in caplog.record_tuples
Exemplo n.º 17
0
    def test_thawing_a_parent_without_children_works(
            self, repo: FakeRepository) -> None:
        """
        Given: A parent without children
        When: Thawing the parent
        Then: The parent is thawed and the first children is breeded
        """
        now = datetime.now()
        task = RecurrentTaskFactory(state="frozen")
        repo.add(task)
        repo.commit()
        selector = TaskSelector(task_ids=[task.id_])

        services.thaw_tasks(repo, selector)  # act

        parent_task = repo.get(task.id_, [RecurrentTask])
        assert parent_task.state == TaskState.BACKLOG
        assert (parent_task.modified - now).total_seconds() < 2
        children_tasks = repo.search({"parent_id": parent_task.id_}, [Task])
        assert len(children_tasks) == 1
Exemplo n.º 18
0
def test_task_report_allows_task_filter(
    repo: Repository,
    config: Config,
    insert_multiple_tasks: List[Task],
    capsys: CaptureFixture[Any],
) -> None:
    """
    Given: Many tasks and only one matches a criteria
    When: The open report is called with that criteria
    Then: Only one task is shown
    """
    task = factories.TaskFactory.create(area="special_area")
    task = Task(description="Description", area="special_area")
    repo.add(task)
    repo.commit()
    task_selector = TaskSelector(task_filter={"area": "special_area"})
    expected_output = [
        r".*",
        r" +ID +│ +Description +│ +Area .*",
        r".*",
        fr" +{task.id_} +│ +{task.description} +│ +{task.area}.*",
        r".*",
    ]

    out, err = run_report(
        "print_task_report",
        {
            "repo": repo,
            "config": config,
            "report_name": "open",
            "task_selector": task_selector,
        },
        capsys,
    )  # act

    assert report_prints_expected(out, expected_output, err)
Exemplo n.º 19
0
    def test_modify_task_modifies_parent_attributes(
        self,
        repo: FakeRepository,
        caplog: LogCaptureFixture,
        faker: Faker,
        insert_parent_task: Tuple[RecurrentTask, Task],
    ) -> None:
        """
        Given: A recurrent task and it's child
        When: modifying the child with modify_parent = True
        Then: Both parent and child attributes are changed.
        """
        parent_task, child_task = insert_parent_task
        selector = TaskSelector(task_ids=[child_task.id_])
        description = faker.sentence()
        change = TaskChanges(task_attributes={"description": description})

        services.modify_tasks(repo, selector, change,
                              modify_parent=True)  # act

        modified_child_task = repo.get(child_task.id_, [Task])
        modified_parent_task = repo.get(parent_task.id_, [RecurrentTask])
        assert modified_child_task.description == description
        assert modified_parent_task.description == description