152 lines
5.0 KiB
Python
152 lines
5.0 KiB
Python
"""Tests for clickup_runner.skill_map."""
|
|
|
|
import pytest
|
|
|
|
from clickup_runner.skill_map import (
|
|
SKILL_MAP,
|
|
SkillRoute,
|
|
get_route,
|
|
get_supported_task_types,
|
|
get_valid_stages,
|
|
)
|
|
|
|
|
|
class TestGetRoute:
|
|
def test_content_creation_run_cora(self):
|
|
route = get_route("Content Creation", "run_cora")
|
|
assert route is not None
|
|
assert route.handler == "autocora"
|
|
assert route.next_stage == "outline"
|
|
assert route.next_status == "review"
|
|
|
|
def test_content_creation_outline(self):
|
|
route = get_route("Content Creation", "outline")
|
|
assert route is not None
|
|
assert route.handler == "claude"
|
|
assert route.skill_file == "content_outline.md"
|
|
assert route.next_stage == "draft"
|
|
|
|
def test_content_creation_draft(self):
|
|
route = get_route("Content Creation", "draft")
|
|
assert route is not None
|
|
assert route.next_stage == "final"
|
|
assert route.max_turns == 30
|
|
|
|
def test_on_page_optimization_has_hidden_div(self):
|
|
route = get_route("On Page Optimization", "hidden div")
|
|
assert route is not None
|
|
assert route.skill_file == "content_hidden_div.md"
|
|
assert route.next_stage == "final"
|
|
|
|
def test_on_page_draft_goes_to_hidden_div(self):
|
|
route = get_route("On Page Optimization", "draft")
|
|
assert route is not None
|
|
assert route.next_stage == "hidden div"
|
|
|
|
def test_press_release_single_stage(self):
|
|
route = get_route("Press Release", "draft")
|
|
assert route is not None
|
|
assert route.skill_file == "press_release_prompt.md"
|
|
assert route.next_stage == "final"
|
|
assert route.next_status == "review"
|
|
|
|
def test_press_release_no_run_cora(self):
|
|
"""Press releases don't need Cora."""
|
|
route = get_route("Press Release", "run_cora")
|
|
assert route is None
|
|
|
|
def test_link_building_run_cora(self):
|
|
route = get_route("Link Building", "run_cora")
|
|
assert route is not None
|
|
assert route.handler == "autocora"
|
|
assert route.next_stage == "build"
|
|
|
|
def test_link_building_build(self):
|
|
route = get_route("Link Building", "build")
|
|
assert route is not None
|
|
assert route.handler == "claude"
|
|
assert route.skill_file == "linkbuilding.md"
|
|
|
|
def test_unknown_task_type_returns_none(self):
|
|
assert get_route("Banana Farming", "draft") is None
|
|
|
|
def test_unknown_stage_returns_none(self):
|
|
assert get_route("Content Creation", "nonexistent") is None
|
|
|
|
def test_stage_is_case_insensitive(self):
|
|
route = get_route("Content Creation", "RUN_CORA")
|
|
assert route is not None
|
|
assert route.handler == "autocora"
|
|
|
|
def test_stage_strips_whitespace(self):
|
|
route = get_route("Content Creation", " outline ")
|
|
assert route is not None
|
|
assert route.handler == "claude"
|
|
|
|
|
|
class TestGetValidStages:
|
|
def test_content_creation(self):
|
|
stages = get_valid_stages("Content Creation")
|
|
assert stages == ["run_cora", "outline", "draft"]
|
|
|
|
def test_on_page_optimization(self):
|
|
stages = get_valid_stages("On Page Optimization")
|
|
assert "hidden div" in stages
|
|
assert len(stages) == 4
|
|
|
|
def test_press_release(self):
|
|
stages = get_valid_stages("Press Release")
|
|
assert stages == ["draft"]
|
|
|
|
def test_link_building(self):
|
|
stages = get_valid_stages("Link Building")
|
|
assert stages == ["run_cora", "build"]
|
|
|
|
def test_unknown_type(self):
|
|
assert get_valid_stages("Nope") == []
|
|
|
|
|
|
class TestGetSupportedTaskTypes:
|
|
def test_returns_all_four(self):
|
|
types = get_supported_task_types()
|
|
assert "Content Creation" in types
|
|
assert "On Page Optimization" in types
|
|
assert "Press Release" in types
|
|
assert "Link Building" in types
|
|
assert len(types) == 4
|
|
|
|
|
|
class TestSkillRouteDataclass:
|
|
def test_defaults(self):
|
|
route = SkillRoute(next_stage="x", next_status="y")
|
|
assert route.handler == "claude"
|
|
assert route.skill_file == ""
|
|
assert route.tools == ""
|
|
assert route.max_turns == 10
|
|
|
|
def test_frozen(self):
|
|
route = SkillRoute(next_stage="x", next_status="y")
|
|
with pytest.raises(AttributeError):
|
|
route.next_stage = "z" # type: ignore[misc]
|
|
|
|
|
|
class TestAllRoutesHaveRequiredFields:
|
|
"""Every route in the map should be well-formed."""
|
|
|
|
@pytest.mark.parametrize(
|
|
"task_type,stage",
|
|
[
|
|
(tt, s)
|
|
for tt, stages in SKILL_MAP.items()
|
|
for s in stages
|
|
],
|
|
)
|
|
def test_route_has_required_fields(self, task_type, stage):
|
|
route = get_route(task_type, stage)
|
|
assert route is not None
|
|
assert route.next_stage, f"{task_type}/{stage} missing next_stage"
|
|
assert route.next_status, f"{task_type}/{stage} missing next_status"
|
|
if route.handler == "claude":
|
|
assert route.skill_file, f"{task_type}/{stage} missing skill_file"
|
|
assert route.tools, f"{task_type}/{stage} missing tools"
|