v9.5: 實作標籤完全不重疊算法

- 新增 _calculate_lane_conflicts_v2() 分開返回標籤重疊和線穿框分數
- 修改泳道選擇算法,優先選擇無標籤重疊的泳道
- 兩階段搜尋:優先側別無可用泳道則嘗試另一側
- 增強日誌輸出,顯示標籤範圍和詳細衝突分數

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
beabigegg
2025-11-06 11:35:29 +08:00
commit 2d37d23bcf
83 changed files with 22971 additions and 0 deletions

146
tests/unit/test_schemas.py Normal file
View File

@@ -0,0 +1,146 @@
"""
資料模型測試
測試 Pydantic schemas 的基本驗證功能
Version: 1.0.0
DocID: TDD-UT-SCHEMA-001
"""
import pytest
from datetime import datetime
from backend.schemas import Event, EventType, TimelineConfig, ExportOptions, ExportFormat
class TestEventModel:
"""Event 模型測試"""
def test_create_valid_event(self):
"""測試建立有效事件"""
event = Event(
id="test-001",
title="測試事件",
start=datetime(2024, 1, 1, 9, 0, 0),
end=datetime(2024, 1, 1, 17, 0, 0),
group="Phase 1",
description="這是一個測試事件",
color="#3B82F6",
event_type=EventType.RANGE
)
assert event.id == "test-001"
assert event.title == "測試事件"
assert event.group == "Phase 1"
assert event.color == "#3B82F6"
def test_event_end_before_start_validation(self):
"""測試結束時間早於開始時間的驗證"""
with pytest.raises(ValueError, match="結束時間必須晚於開始時間"):
Event(
id="test-002",
title="無效事件",
start=datetime(2024, 1, 2, 9, 0, 0),
end=datetime(2024, 1, 1, 9, 0, 0), # 結束早於開始
)
def test_event_with_invalid_color(self):
"""測試無效的顏色格式"""
with pytest.raises(ValueError):
Event(
id="test-003",
title="測試事件",
start=datetime(2024, 1, 1, 9, 0, 0),
color="invalid-color" # 無效的顏色格式
)
def test_event_optional_fields(self):
"""測試可選欄位"""
event = Event(
id="test-004",
title="最小事件",
start=datetime(2024, 1, 1, 9, 0, 0)
)
assert event.end is None
assert event.group is None
assert event.description is None
assert event.color is None
class TestTimelineConfig:
"""TimelineConfig 模型測試"""
def test_default_config(self):
"""測試預設配置"""
config = TimelineConfig()
assert config.direction == 'horizontal'
assert config.theme.value == 'modern'
assert config.show_grid is True
assert config.show_tooltip is True
def test_custom_config(self):
"""測試自訂配置"""
config = TimelineConfig(
direction='vertical',
theme='classic',
show_grid=False
)
assert config.direction == 'vertical'
assert config.theme.value == 'classic'
assert config.show_grid is False
class TestExportOptions:
"""ExportOptions 模型測試"""
def test_valid_export_options(self):
"""測試有效的匯出選項"""
options = ExportOptions(
fmt=ExportFormat.PDF,
dpi=300,
width=1920,
height=1080
)
assert options.fmt == ExportFormat.PDF
assert options.dpi == 300
assert options.width == 1920
assert options.height == 1080
def test_dpi_range_validation(self):
"""測試 DPI 範圍驗證"""
# DPI 太低
with pytest.raises(ValueError):
ExportOptions(
fmt=ExportFormat.PNG,
dpi=50 # < 72
)
# DPI 太高
with pytest.raises(ValueError):
ExportOptions(
fmt=ExportFormat.PNG,
dpi=700 # > 600
)
def test_dimension_validation(self):
"""測試尺寸範圍驗證"""
# 寬度太小
with pytest.raises(ValueError):
ExportOptions(
fmt=ExportFormat.PNG,
width=500 # < 800
)
# 高度太大
with pytest.raises(ValueError):
ExportOptions(
fmt=ExportFormat.PNG,
height=5000 # > 4096
)
if __name__ == "__main__":
pytest.main([__file__, "-v"])