-module(logic_booking_tests). -include_lib("eunit/include/eunit.hrl"). -include("records.hrl"). -define(TEST_EMAIL, <<"test@example.com">>). setup() -> mnesia:start(), mnesia:create_table(user, [ {attributes, record_info(fields, user)}, {ram_copies, [node()]} ]), mnesia:create_table(calendar, [ {attributes, record_info(fields, calendar)}, {ram_copies, [node()]} ]), mnesia:create_table(event, [ {attributes, record_info(fields, event)}, {ram_copies, [node()]} ]), mnesia:create_table(booking, [ {attributes, record_info(fields, booking)}, {ram_copies, [node()]} ]), ok. cleanup(_) -> mnesia:delete_table(booking), mnesia:delete_table(event), mnesia:delete_table(calendar), mnesia:delete_table(user), mnesia:stop(), ok. logic_booking_test_() -> {foreach, fun setup/0, fun cleanup/1, [ {"Create booking with auto confirmation", fun test_create_booking_auto/0}, {"Create booking with manual confirmation", fun test_create_booking_manual/0}, {"Create booking with timeout confirmation", fun test_create_booking_timeout/0}, {"Create duplicate booking", fun test_create_duplicate_booking/0}, {"Create booking for inactive event", fun test_booking_inactive_event/0}, {"Create booking when event is full", fun test_booking_event_full/0}, {"Confirm booking by owner", fun test_confirm_booking/0}, {"Decline booking by owner", fun test_decline_booking/0}, {"Cancel booking by participant", fun test_cancel_booking/0}, {"Unauthorized confirm attempt", fun test_unauthorized_confirm/0}, {"List event bookings", fun test_list_event_bookings/0}, {"List user bookings", fun test_list_user_bookings/0} ]}. %% Вспомогательные функции create_test_user(Role) -> UserId = base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}), User = #user{ id = UserId, email = <>, password_hash = <<"hash">>, role = Role, status = active, created_at = calendar:universal_time(), updated_at = calendar:universal_time() }, mnesia:dirty_write(User), UserId. create_test_calendar(OwnerId, Confirmation) -> {ok, Calendar} = core_calendar:create(OwnerId, <<"Test Calendar">>, <<"">>, Confirmation), Calendar#calendar.id. create_test_event(CalendarId) -> StartTime = {{2026, 6, 1}, {10, 0, 0}}, {ok, Event} = core_event:create(CalendarId, <<"Test Event">>, StartTime, 60), Event#event.id. create_test_event_with_capacity(CalendarId, Capacity) -> StartTime = {{2026, 6, 1}, {10, 0, 0}}, {ok, Event} = core_event:create(CalendarId, <<"Test Event">>, StartTime, 60), {ok, Updated} = core_event:update(Event#event.id, [{capacity, Capacity}]), Updated#event.id. %% Тесты test_create_booking_auto() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, auto), EventId = create_test_event(CalendarId), {ok, Booking} = logic_booking:create_booking(ParticipantId, EventId), timer:sleep(100), {ok, Updated} = core_booking:get_by_id(Booking#booking.id), ?assertEqual(confirmed, Updated#booking.status). test_create_booking_manual() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, Booking} = logic_booking:create_booking(ParticipantId, EventId), ?assertEqual(pending, Booking#booking.status). test_create_booking_timeout() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, {timeout, 1}), EventId = create_test_event(CalendarId), {ok, Booking} = logic_booking:create_booking(ParticipantId, EventId), ?assertEqual(pending, Booking#booking.status), timer:sleep(1500), {ok, Updated} = core_booking:get_by_id(Booking#booking.id), ?assertEqual(confirmed, Updated#booking.status). test_create_duplicate_booking() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, _} = logic_booking:create_booking(ParticipantId, EventId), {error, already_booked} = logic_booking:create_booking(ParticipantId, EventId). test_booking_inactive_event() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, _} = core_event:update(EventId, [{status, cancelled}]), {error, event_not_active} = logic_booking:create_booking(ParticipantId, EventId). test_booking_event_full() -> OwnerId = create_test_user(user), Participant1Id = create_test_user(user), Participant2Id = create_test_user(user), CalendarId = create_test_calendar(OwnerId, auto), EventId = create_test_event_with_capacity(CalendarId, 1), {ok, _} = logic_booking:create_booking(Participant1Id, EventId), {error, event_full} = logic_booking:create_booking(Participant2Id, EventId). test_confirm_booking() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, Booking} = logic_booking:create_booking(ParticipantId, EventId), {ok, Confirmed} = logic_booking:confirm_booking(OwnerId, Booking#booking.id, confirm), ?assertEqual(confirmed, Confirmed#booking.status). test_decline_booking() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, Booking} = logic_booking:create_booking(ParticipantId, EventId), {ok, Declined} = logic_booking:confirm_booking(OwnerId, Booking#booking.id, decline), ?assertEqual(cancelled, Declined#booking.status). test_cancel_booking() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, Booking} = logic_booking:create_booking(ParticipantId, EventId), {ok, Cancelled} = logic_booking:cancel_booking(ParticipantId, Booking#booking.id), ?assertEqual(cancelled, Cancelled#booking.status). test_unauthorized_confirm() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), OtherId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, Booking} = logic_booking:create_booking(ParticipantId, EventId), {error, access_denied} = logic_booking:confirm_booking(OtherId, Booking#booking.id, confirm). test_list_event_bookings() -> OwnerId = create_test_user(user), Participant1Id = create_test_user(user), Participant2Id = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId = create_test_event(CalendarId), {ok, _} = logic_booking:create_booking(Participant1Id, EventId), {ok, _} = logic_booking:create_booking(Participant2Id, EventId), {ok, Bookings} = logic_booking:list_event_bookings(OwnerId, EventId), ?assertEqual(2, length(Bookings)). test_list_user_bookings() -> OwnerId = create_test_user(user), ParticipantId = create_test_user(user), CalendarId = create_test_calendar(OwnerId, manual), EventId1 = create_test_event(CalendarId), EventId2 = create_test_event(CalendarId), {ok, _} = logic_booking:create_booking(ParticipantId, EventId1), {ok, _} = logic_booking:create_booking(ParticipantId, EventId2), {ok, Bookings} = logic_booking:list_user_bookings(ParticipantId), ?assertEqual(2, length(Bookings)).