refactor(deck): address PR #826 review feedback
- Modernize the new models (DeckCardSummary, DeckCommentSummary, StackOverview, BoardOverviewResponse + the loosened unions) to PEP 604 syntax (list[...] / X | None), per CLAUDE.md. - Make status="done" exclude archived cards so open/done/archived partition the board with no overlap (a done+archived card is reported only as "archived"); document the semantics in docstrings and docs/deck.md, add a partition unit test. - deck_get_archived_stacks: pass through label/assigned_to filters (status stays archived-only by definition); note the limitation in the docstring. - Rename _validate_description_max_length → _validate_positive_length (now a generic positive-length guard). - Soften deck_get_board_overview docstring: it views board state and omits the ACL/user/label-management fields deck_get_board exposes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b11103064c
commit
d2da195172
@@ -28,7 +28,7 @@ from nextcloud_mcp_server.server.deck import (
|
||||
_summarize_card,
|
||||
_truncate_card_descriptions,
|
||||
_truncate_comment_message,
|
||||
_validate_description_max_length,
|
||||
_validate_positive_length,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
@@ -182,30 +182,30 @@ def test_truncate_card_descriptions_shorter_than_limit_no_ellipsis():
|
||||
assert cards[0].description == "hello"
|
||||
|
||||
|
||||
# _validate_description_max_length ----------------------------------------
|
||||
# _validate_positive_length ----------------------------------------
|
||||
|
||||
|
||||
def test_validate_description_max_length_accepts_none():
|
||||
def test_validate_positive_length_accepts_none():
|
||||
"""None is the documented sentinel for "no truncation"."""
|
||||
_validate_description_max_length(None)
|
||||
_validate_positive_length(None)
|
||||
|
||||
|
||||
def test_validate_description_max_length_accepts_positive():
|
||||
def test_validate_positive_length_accepts_positive():
|
||||
"""Positive values pass through silently."""
|
||||
_validate_description_max_length(1)
|
||||
_validate_description_max_length(1000)
|
||||
_validate_positive_length(1)
|
||||
_validate_positive_length(1000)
|
||||
|
||||
|
||||
def test_validate_description_max_length_rejects_zero():
|
||||
def test_validate_positive_length_rejects_zero():
|
||||
"""Zero would wipe descriptions to a single ellipsis — reject at the boundary."""
|
||||
with pytest.raises(ValueError, match="must be positive"):
|
||||
_validate_description_max_length(0)
|
||||
_validate_positive_length(0)
|
||||
|
||||
|
||||
def test_validate_description_max_length_rejects_negative():
|
||||
def test_validate_positive_length_rejects_negative():
|
||||
"""Negative values produce surprising slice semantics — reject at the boundary."""
|
||||
with pytest.raises(ValueError, match="must be positive"):
|
||||
_validate_description_max_length(-10)
|
||||
_validate_positive_length(-10)
|
||||
|
||||
|
||||
# _apply_board_filters ------------------------------------------------------
|
||||
@@ -299,8 +299,8 @@ def test_filter_cards_open_excludes_archived_and_done():
|
||||
assert [c.id for c in result] == [1]
|
||||
|
||||
|
||||
def test_filter_cards_done_keeps_only_done():
|
||||
"""status="done" keeps only cards with a done timestamp."""
|
||||
def test_filter_cards_done_keeps_only_done_and_not_archived():
|
||||
"""status="done" keeps done cards that are not archived."""
|
||||
done_at = datetime(2024, 1, 1, tzinfo=timezone.utc)
|
||||
cards = [_make_card(1), _make_card(2, done=done_at)]
|
||||
result = _filter_cards(cards, status="done", label=None, assigned_to=None)
|
||||
@@ -314,6 +314,27 @@ def test_filter_cards_archived_keeps_only_archived():
|
||||
assert [c.id for c in result] == [2]
|
||||
|
||||
|
||||
def test_filter_cards_statuses_partition_the_board():
|
||||
"""open/done/archived are non-overlapping; a done+archived card counts
|
||||
only as "archived", not "done"."""
|
||||
done_at = datetime(2024, 1, 1, tzinfo=timezone.utc)
|
||||
open_card = _make_card(1)
|
||||
done_card = _make_card(2, done=done_at)
|
||||
done_and_archived = _make_card(3, done=done_at, archived=True)
|
||||
cards = [open_card, done_card, done_and_archived]
|
||||
|
||||
assert [
|
||||
c.id for c in _filter_cards(cards, status="open", label=None, assigned_to=None)
|
||||
] == [1]
|
||||
assert [
|
||||
c.id for c in _filter_cards(cards, status="done", label=None, assigned_to=None)
|
||||
] == [2]
|
||||
assert [
|
||||
c.id
|
||||
for c in _filter_cards(cards, status="archived", label=None, assigned_to=None)
|
||||
] == [3]
|
||||
|
||||
|
||||
def test_filter_cards_all_keeps_everything():
|
||||
"""status="all" applies no status filter."""
|
||||
cards = [_make_card(1), _make_card(2, archived=True)]
|
||||
|
||||
Reference in New Issue
Block a user