"""#11 Bootstrap 四段式拼装单元测试(v2.1) 覆盖: - T1: build(role, task_context) 4 段结构 - T2: token 估算 + 预算告警 - T3: 缺失组件降级 - T4: build_for_task 便捷方法 """ import pytest pytestmark = pytest.mark.unit from unittest.mock import patch from pathlib import Path from src.daemon.bootstrap import BootstrapBuilder, estimate_tokens @pytest.fixture def builder(): return BootstrapBuilder(max_tokens=4096) # --------------------------------------------------------------------------- # T1: build(role, task_context) 4 段结构 # --------------------------------------------------------------------------- class TestFourSectionBuild: def test_basic_executor_build(self, builder): b = builder.build( role="executor", task_context={"task_id": "t1", "title": "Write tests", "description": "Write unit tests", "must_haves": "100% coverage", "status": "claimed"}, ) # 段: 任务上下文 assert "Write tests" in b assert "t1" in b assert "100% coverage" in b def test_basic_reviewer_build(self, builder): b = builder.build( role="reviewer", task_context={"task_id": "t2", "title": "Review PR"}, ) assert "Review PR" in b def test_planner_build(self, builder): b = builder.build( role="planner", task_context={"task_id": "t3", "title": "Plan sprint"}, ) assert "Plan sprint" in b def test_depends_on_outputs_injected(self, builder): b = builder.build( role="executor", task_context={ "title": "T", "depends_on_outputs": [ {"task_id": "t0", "summary": "Data downloaded"}, ], }, ) assert "前序产出" in b assert "Data downloaded" in b def test_no_depends_on_omitted(self, builder): b = builder.build( role="executor", task_context={"title": "T"}, ) assert "前序产出" not in b # --------------------------------------------------------------------------- # T2: token 估算 + 预算告警 # --------------------------------------------------------------------------- class TestTokenEstimation: def test_estimate_tokens_basic(self): assert estimate_tokens("hello") > 0 def test_estimate_tokens_long_text(self): text = "a" * 1000 tokens = estimate_tokens(text) assert 200 < tokens < 400 # --------------------------------------------------------------------------- # T3: 缺失组件降级 # --------------------------------------------------------------------------- class TestGracefulDegradation: def test_empty_task(self, builder): b = builder.build(role="executor", task_context={}) assert b # 不为空 assert "# Role: executor" in b def test_partial_task(self, builder): b = builder.build(role="executor", task_context={"title": "Only title"}) assert "Only title" in b # --------------------------------------------------------------------------- # T4: build_for_task 便捷方法 # --------------------------------------------------------------------------- class TestBuildForTask: def test_build_for_task_object(self, builder): """用 mock task 对象测试 build_for_task""" class MockTask: id = "t1" title = "Build Feature" description = "Implement X with tests" must_haves = "Unit tests, Documentation" task_type = "coding" risk_level = "low" task = MockTask() b = builder.build_for_task(task, role="executor") assert "Build Feature" in b assert "Implement X" in b def test_build_for_task_ignores_kwargs(self, builder): """build_for_task accepts project_config and experiences""" class MockTask: id = "t1" title = "T" description = "" must_haves = "" task_type = "coding" risk_level = "low" task = MockTask() # project_config/experiences are valid kwargs for build_for_task b = builder.build_for_task( task, role="executor", project_config={"name": "Old"}, experiences=[{"x": 1}], ) assert "T" in b