from __future__ import annotations from datetime import date, time import pytest from pydantic import ValidationError from app.schemas.itinerary import ( DailyItinerary, FlightSelection, HotelSelection, ItineraryActivity, ItineraryPlan, ) def build_plan() -> ItineraryPlan: return ItineraryPlan( title="上海至成都四日旅行", overview="轻松游览成都代表性景点。", selected_flight=FlightSelection( flight_type="round_trip", combination_id="round-001", outbound_option_id="out-001", return_option_id="ret-001", quoted_price=1800, currency="CNY", selection_reason="综合价格与时间。", ), selected_hotel=HotelSelection( hotel_id="hotel-001", name="测试酒店", check_in_date=date(2026, 8, 10), check_out_date=date(2026, 8, 13), nights=3, price_per_night=500, estimated_total_price=1500, currency="CNY", selection_reason="靠近主要景点。", ), days=[ DailyItinerary( day_index=1, date=date(2026, 8, 10), theme="抵达成都", activities=[ ItineraryActivity( sequence=1, activity_type="flight", name="前往成都", start_time=time(9, 0), end_time=time(12, 0), ) ], ) ], ) def test_valid_itinerary_plan() -> None: plan = build_plan() assert plan.selected_hotel.nights == 3 assert plan.selected_flight.quoted_price == 1800 assert len(plan.days) == 1 def test_round_trip_requires_return_option() -> None: with pytest.raises(ValidationError): FlightSelection( flight_type="round_trip", combination_id="round-001", outbound_option_id="out-001", return_option_id=None, selection_reason="测试", ) def test_duplicate_day_date_is_rejected() -> None: plan = build_plan() duplicate_day = plan.days[0].model_copy( update={ "day_index": 2, } ) with pytest.raises(ValidationError): ItineraryPlan( title=plan.title, overview=plan.overview, selected_flight=( plan.selected_flight ), selected_hotel=( plan.selected_hotel ), days=[ plan.days[0], duplicate_day, ], )