""" 完整测试 - 验证部分時間視窗支持 测试所有真实场景 """ from datetime import datetime import sys # 导入修复后的模型 try: from src.optimization.models.internal_models import _POICandidate, _Task print("✅ 成功导入 final_internal_models\n") except ImportError as e: print(f"❌ 导入失败: {e}") sys.exit(1) def test_real_world_scenarios(): """测试真实业务场景""" print("=" * 60) print("真实业务场景测试") print("=" * 60) print() dt_start = datetime(2025, 11, 18, 9, 0) dt_end = datetime(2025, 11, 18, 15, 0) # 场景 1: 24小时便利店(无时间限制) print("場景 1: 24小時便利商店") print(" 輸入: time_window = None") poi1 = _POICandidate( poi_id="7-11", lat=25.0408, lng=121.5318, time_window=None ) print(f" 結果: {poi1.time_window}") print(" ✅ 通過\n") # 场景 2: 只有营业结束时间的餐厅 print("場景 2: 餐廳(營業到晚上10點,沒有開始限制)") print(" 結果: time_window = (None, 22:00)") poi2 = _POICandidate( poi_id="restaurant", lat=25.0408, lng=121.5318, time_window=(None, datetime(2025, 11, 18, 22, 0)) ) print(f" 結果: {poi2.time_window}") assert poi2.time_window == (None, datetime(2025, 11, 18, 22, 0)) print(" ✅ 通過 - 保留部分時間窗口\n") # 场景 3: 只有营业开始时间的配送服务 print("場景 3: 配送服務(早上6點開始,沒有結束限制)") print(" 輸入: time_window = (06:00, None)") poi3 = _POICandidate( poi_id="delivery", lat=25.0408, lng=121.5318, time_window=(datetime(2025, 11, 18, 6, 0), None) ) print(f" 結果: {poi3.time_window}") assert poi3.time_window == (datetime(2025, 11, 18, 6, 0), None) print(" ✅ 通過 - 保留部分時間窗口\n") # 场景 4: 标准营业时间 print("場景 4: 標準營業時間(09:00-17:00)") print(" 輸入: time_window = (09:00, 17:00)") poi4 = _POICandidate( poi_id="office", lat=25.0408, lng=121.5318, time_window=(dt_start, datetime(2025, 11, 18, 17, 0)) ) print(f" 結果: {poi4.time_window}") assert poi4.time_window == (dt_start, datetime(2025, 11, 18, 17, 0)) print(" ✅ 通過 - 完整時間窗口\n") # 场景 5: (None, None) 应该转为 None) print("場景 5: 完全無限制") print(" 輸入: time_window = (None, None)") poi5 = _POICandidate( poi_id="flexible", lat=25.0408, lng=121.5318, time_window=(None, None) ) print(f" 結果: {poi5.time_window}") assert poi5.time_window is None print(" ✅ 通過 - 轉為 None\n") def test_multiple_time_windows(): """测试多段時間視窗""" print("=" * 60) print("多段時間視窗測試") print("=" * 60) print() dt1_start = datetime(2025, 11, 18, 9, 0) dt1_end = datetime(2025, 11, 18, 12, 0) dt2_start = datetime(2025, 11, 18, 14, 0) dt2_end = datetime(2025, 11, 18, 17, 0) # 场景 1: 午休的商店(上午 + 下午) print("場景 1: 有午休的商店") print(" 輸入: time_windows = [(09:00-12:00), (14:00-17:00)]") poi = _POICandidate( poi_id="shop_with_lunch_break", lat=25.0408, lng=121.5318, time_windows=[ (dt1_start, dt1_end), (dt2_start, dt2_end) ] ) print(f" 結果: {poi.time_windows}") assert len(poi.time_windows) == 2 print(" ✅ 通過\n") # 场景 2: 包含部分時間視窗 print("場景 2: 混合時間窗口") print(" 輸入: time_windows = [(09:00-12:00), (None, 22:00)]") poi = _POICandidate( poi_id="mixed", lat=25.0408, lng=121.5318, time_windows=[ (dt1_start, dt1_end), (None, datetime(2025, 11, 18, 22, 0)) ] ) print(f" 結果: {poi.time_windows}") assert len(poi.time_windows) == 2 print(" ✅ 場景 2: 混合時間窗口\n") # 场景 3: 過滤 (None, None) print("場景 3: 包含無效視窗") print(" 輸入: time_windows = [(09:00-12:00), (None, None)]") poi = _POICandidate( poi_id="with_invalid", lat=25.0408, lng=121.5318, time_windows=[ (dt1_start, dt1_end), (None, None) ] ) print(f" 結果: {poi.time_windows}") assert len(poi.time_windows) == 1 assert poi.time_windows[0] == (dt1_start, dt1_end) print(" ✅ 通過 - 過濾掉 (None, None)\n") def test_validation_logic(): """测试验证逻辑""" print("=" * 60) print("驗證邏輯測試") print("=" * 60) print() # 测试 1: start > end 应该失败 print("测试 1: start > end (应该报错)") try: poi = _POICandidate( poi_id="invalid", lat=25.0408, lng=121.5318, time_window=( datetime(2025, 11, 18, 17, 0), datetime(2025, 11, 18, 9, 0) ) ) print(" ❌ 沒有報錯(應該要報錯)\n") except ValueError as e: print(f" 結果: {e}") print(" ✅ 正確報錯\n") # 测试 2: start = end 应该失败 print("測試 2: start = end (應該報錯)") try: poi = _POICandidate( poi_id="invalid", lat=25.0408, lng=121.5318, time_window=( datetime(2025, 11, 18, 9, 0), datetime(2025, 11, 18, 9, 0) ) ) print(" ❌ 沒有報錯(應該報錯)\n") except ValueError as e: print(f" 結果: {e}") print(" ✅ 正確報錯\n") # 测试 3: 部分時間視窗不需要验证 print("測試 3: 部分時間視窗 (None, datetime) - 無需驗證") poi = _POICandidate( poi_id="partial", lat=25.0408, lng=121.5318, time_window=(None, datetime(2025, 11, 18, 22, 0)) ) print(f" 結果: {poi.time_window}") print(" ✅ 通過 \n") def test_task_time_window(): """测试 Task 的時間視窗""" print("=" * 60) print("Task 時間窗口測試") print("=" * 60) print() dt_start = datetime(2025, 11, 18, 9, 0) dt_end = datetime(2025, 11, 18, 15, 0) # 测试 1: 完整時間視窗 print("測試 1: Task 完整時間窗口") task = _Task( task_id="task_1", priority="HIGH", time_window=(dt_start, dt_end), service_duration_min=45, candidates=[ _POICandidate( poi_id="poi_1", lat=25.0408, lng=121.5318 ) ] ) print(f" 結果: {task.time_window}") assert task.time_window == (dt_start, dt_end) print(" ✅ 通過\n") # 测试 2: 部分時間視窗 print("测试 2: Task 部分時間窗口") task = _Task( task_id="task_2", priority="MEDIUM", time_window=(None, dt_end), service_duration_min=30, candidates=[ _POICandidate( poi_id="poi_2", lat=25.0408, lng=121.5318 ) ] ) print(f" 結果: {task.time_window}") assert task.time_window == (None, dt_end) print(" ✅ 通過\n") def main(): print("\n") print("╔" + "=" * 58 + "╗") print("║" + " " * 15 + "時間窗口完整測試" + " " * 15 + "║") print("╚" + "=" * 58 + "╝") print("\n") try: test_real_world_scenarios() test_multiple_time_windows() test_validation_logic() test_task_time_window() print("\n") print("╔" + "=" * 58 + "╗") print("║" + " " * 18 + "✅ 所有测试通過" + " " * 18 + "║") print("╚" + "=" * 58 + "╝") print("\n") print("总结:") print("✅ 支持完整時間視窗: (datetime, datetime)") print("✅ 支持部分時間視窗: (None, datetime) 或 (datetime, None)") print("✅ 支持無限制: None 或 (None, None)") print("✅ 正确過滤無效窗口") print("\n") except Exception as e: print(f"\n❌ 測試失敗: {e}") import traceback traceback.print_exc() sys.exit(1) if __name__ == "__main__": main()