Skip to content

Commit

Permalink
Finish testing the WorkingSet API (#28)
Browse files Browse the repository at this point in the history
Aside from a missing `__repr__`, this API was already in good shape, but
not completely tested.
  • Loading branch information
djmitche authored Jan 3, 2025
1 parent ecffd73 commit f9b3865
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 44 deletions.
2 changes: 1 addition & 1 deletion src/replica.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl Replica {
}

pub fn working_set(&mut self) -> anyhow::Result<WorkingSet> {
Ok(self.0.working_set().map(WorkingSet)?)
Ok(self.0.working_set().map(WorkingSet::from)?)
}

pub fn dependency_map(&mut self, force: bool) -> anyhow::Result<DependencyMap> {
Expand Down
39 changes: 36 additions & 3 deletions src/working_set.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::fmt;

use pyo3::prelude::*;
use taskchampion::Uuid;
use taskchampion::WorkingSet as TCWorkingSet;
// TODO: convert working set into python's iterable type

#[pyclass]
pub struct WorkingSet(pub(crate) TCWorkingSet);
pub struct WorkingSet(TCWorkingSet);

#[pyclass]
struct WorkingSetIter {
Expand All @@ -26,6 +28,10 @@ impl WorkingSet {
self.0.len()
}

pub fn __repr__(&self) -> String {
format!("{:?}", self)
}

pub fn largest_index(&self) -> usize {
self.0.largest_index()
}
Expand All @@ -39,7 +45,6 @@ impl WorkingSet {
}

pub fn by_uuid(&self, uuid: String) -> Option<usize> {
// TODO I don't like the conversion, should use try-expect or something else as an input
self.0.by_uuid(Uuid::parse_str(&uuid).unwrap())
}

Expand All @@ -55,3 +60,31 @@ impl WorkingSet {
Py::new(slf.py(), iter)
}
}

// TODO: Use the Taskchampion Debug implementation when
// https://github.com/GothenburgBitFactory/taskchampion/pull/520 is available.
impl fmt::Debug for WorkingSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("WorkingSet {")?;
f.debug_list().entries(self.0.iter()).finish()?;
f.write_str("}")
}
}

impl AsRef<TCWorkingSet> for WorkingSet {
fn as_ref(&self) -> &TCWorkingSet {
&self.0
}
}

impl From<TCWorkingSet> for WorkingSet {
fn from(value: TCWorkingSet) -> Self {
WorkingSet(value)
}
}

impl From<WorkingSet> for TCWorkingSet {
fn from(value: WorkingSet) -> Self {
value.0
}
}
1 change: 0 additions & 1 deletion taskchampion.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ class WorkingSet:
def by_index(self, index: int) -> Optional[str]: ...
def by_uuid(self, uuid: str) -> Optional[int]: ...
def __iter__(self) -> Iterator[tuple[int, str]]: ...
def __next__(self) -> tuple[int, str]: ...

class Annotation:
entry: datetime
Expand Down
20 changes: 0 additions & 20 deletions tests/test_replica.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,6 @@ def test_all_tasks(empty_replica: Replica):
assert tasks[key] != 0


def test_working_set(replica_with_tasks: Replica):
ws = replica_with_tasks.working_set()

assert ws is not None


# TODO: create testable and inspectable WorkingSet


def test_get_task(replica_with_tasks: Replica):
uuid = replica_with_tasks.all_task_uuids()[0]

Expand All @@ -102,17 +93,6 @@ def test_get_task(replica_with_tasks: Replica):
assert task is not None


@pytest.mark.skip()
def test_rebuild_working_set(replica_with_tasks: Replica):
# TODO actually test this
replica_with_tasks.rebuild_working_set(False)


@pytest.mark.skip()
def test_add_undo_point(replica_with_tasks: Replica):
replica_with_tasks.add_undo_point(False)


def test_num_local_operations(replica_with_tasks: Replica):
assert replica_with_tasks.num_local_operations() == 3

Expand Down
61 changes: 42 additions & 19 deletions tests/test_working_set.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,71 @@
from taskchampion import Replica, WorkingSet, Status, Operations
from pathlib import Path
import pytest
import re
import uuid


@pytest.fixture
def working_set():
def uuids():
return [str(uuid.uuid4()) for _ in range(0, 5)]


@pytest.fixture
def working_set(uuids: list[str]):
r = Replica.new_in_memory()

ops = Operations()
task = r.create_task(str(uuid.uuid4()), ops)
task.set_status(Status.Pending, ops)
task = r.create_task(str(uuid.uuid4()), ops)
task.set_status(Status.Pending, ops)
task.start(ops)
task1 = r.create_task(uuids[1], ops)
task1.set_status(Status.Pending, ops)
task2 = r.create_task(uuids[2], ops)
task2.set_status(Status.Pending, ops)
task2.start(ops)
task3 = r.create_task(uuids[3], ops)
task3.set_status(Status.Pending, ops)
task4 = r.create_task(uuids[4], ops)
task4.set_status(Status.Pending, ops)
r.commit_operations(ops)

# Remove task 3 from working set
ops = Operations()
task3.set_status(Status.Completed, ops)
r.commit_operations(ops)
r.rebuild_working_set(False)

return r.working_set()


def test_len(working_set: WorkingSet):
assert len(working_set) == 2
assert len(working_set) == 3


def test_repr(working_set: WorkingSet):
# The Rust Debug output contains lots of internal details that we do not
# need to check for here.
assert re.match(r"^WorkingSet {.*}$", repr(working_set))


def test_largest_index(working_set: WorkingSet):
assert working_set.largest_index() == 2
assert working_set.largest_index() == 4


def test_is_empty(working_set: WorkingSet):
assert not working_set.is_empty()


def test_by_index(working_set: WorkingSet):
assert working_set.by_index(1) is not None

def test_by_index(working_set: WorkingSet, uuids: list[str]):
assert working_set.by_index(1) == uuids[1]
assert working_set.by_index(2) == uuids[2]
assert working_set.by_index(3) == None
assert working_set.by_index(4) == uuids[4]

def test_iter(working_set: WorkingSet):
assert iter(working_set)

def test_by_uuid(working_set: WorkingSet, uuids: list[str]):
assert working_set.by_uuid(uuids[1]) == 1
assert working_set.by_uuid(uuids[2]) == 2
assert working_set.by_uuid(uuids[3]) == None
assert working_set.by_uuid(uuids[4]) == 4

def test_next(working_set: WorkingSet):
working_set_iterator = iter(working_set)

assert next(working_set_iterator)[0] == 1
assert next(working_set_iterator)[0] == 2
with pytest.raises(StopIteration):
next(working_set_iterator)
def test_iter(working_set: WorkingSet, uuids: list[str]):
assert list(working_set) == [(1, uuids[1]), (2, uuids[2]), (4, uuids[4])]

0 comments on commit f9b3865

Please sign in to comment.