Stage 10 final

This commit is contained in:
2026-04-22 23:15:20 +03:00
parent e3a08cfa04
commit 081dcf9588
85 changed files with 2116 additions and 160 deletions

View File

@@ -0,0 +1,249 @@
-module(logic_search_tests).
-include_lib("eunit/include/eunit.hrl").
-include("records.hrl").
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()]}
]),
ok.
cleanup(_) ->
mnesia:delete_table(event),
mnesia:delete_table(calendar),
mnesia:delete_table(user),
mnesia:stop(),
ok.
logic_search_test_() ->
{foreach,
fun setup/0,
fun cleanup/1,
[
{"Search events by text", fun test_search_events_by_text/0},
{"Search events by tags", fun test_search_events_by_tags/0},
{"Search events by date range", fun test_search_events_by_date/0},
{"Search events by location", fun test_search_events_by_location/0},
{"Combined search", fun test_combined_search/0},
{"Search calendars", fun test_search_calendars/0},
{"Search all", fun test_search_all/0},
{"Pagination", fun test_pagination/0},
{"Sorting", fun test_sorting/0},
{"Access control in search", fun test_access_control/0},
{"Empty search results", fun test_empty_search/0}
]}.
%% Вспомогательные функции
create_test_user(Role) ->
UserId = base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}),
User = #user{
id = UserId,
email = <<UserId/binary, "@test.com">>,
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, Type, Tags) ->
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test Calendar">>, <<"Description">>, manual),
core_calendar:update(Calendar#calendar.id, [{type, Type}, {tags, Tags}]),
{ok, Updated} = core_calendar:get_by_id(Calendar#calendar.id),
Updated#calendar.id.
create_test_event(CalendarId, Title, Description, StartTime, Tags, Location) ->
{ok, Event} = core_event:create(CalendarId, Title, StartTime, 60),
Updates = [{description, Description}, {tags, Tags}],
Updates2 = case Location of
undefined -> Updates;
_ -> [{location, Location} | Updates]
end,
core_event:update(Event#event.id, Updates2),
{ok, Updated} = core_event:get_by_id(Event#event.id),
Updated#event.id.
%% Тесты
test_search_events_by_text() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
create_test_event(CalendarId, <<"Python Workshop">>, <<"Learn Python">>, StartTime, [], undefined),
create_test_event(CalendarId, <<"JavaScript Conference">>, <<"JS for everyone">>, StartTime, [], undefined),
create_test_event(CalendarId, <<"Yoga Class">>, <<"Morning yoga">>, StartTime, [], undefined),
Params = #{},
{ok, Total, Results} = logic_search:search(<<"event">>, <<"Python">>, OwnerId, Params),
?assertEqual(1, Total),
?assertEqual(1, length(Results)),
{ok, Total2, _Results2} = logic_search:search(<<"event">>, <<"conference">>, OwnerId, Params),
?assertEqual(1, Total2).
test_search_events_by_tags() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
create_test_event(CalendarId, <<"Event 1">>, <<"">>, StartTime, [<<"python">>, <<"workshop">>], undefined),
create_test_event(CalendarId, <<"Event 2">>, <<"">>, StartTime, [<<"javascript">>, <<"conference">>], undefined),
create_test_event(CalendarId, <<"Event 3">>, <<"">>, StartTime, [<<"python">>, <<"advanced">>], undefined),
% Поиск по одному тегу
Params = #{tags => <<"python">>},
{ok, Total, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
?assertEqual(2, Total), % Event 1 и Event 3
% Поиск по тегу, который есть только у одного события
Params2 = #{tags => <<"workshop">>},
{ok, Total2, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
?assertEqual(1, Total2), % Только Event 1
% Поиск по тегу, которого нет
Params3 = #{tags => <<"nonexistent">>},
{ok, Total3, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params3),
?assertEqual(0, Total3).
test_search_events_by_date() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
create_test_event(CalendarId, <<"June Event">>, <<"">>, {{2026, 6, 15}, {10, 0, 0}}, [], undefined),
create_test_event(CalendarId, <<"July Event">>, <<"">>, {{2026, 7, 15}, {10, 0, 0}}, [], undefined),
create_test_event(CalendarId, <<"August Event">>, <<"">>, {{2026, 8, 15}, {10, 0, 0}}, [], undefined),
Params = #{from => {{2026, 6, 1}, {0, 0, 0}}, to => {{2026, 6, 30}, {23, 59, 59}}},
{ok, Total, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
?assertEqual(1, Total).
test_search_events_by_location() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
MoscowLoc = #location{address = <<"Moscow">>, lat = 55.7558, lon = 37.6173},
SpbLoc = #location{address = <<"SPb">>, lat = 59.9343, lon = 30.3351},
create_test_event(CalendarId, <<"Moscow Event">>, <<"">>, StartTime, [], MoscowLoc),
create_test_event(CalendarId, <<"SPb Event">>, <<"">>, StartTime, [], SpbLoc),
Params = #{lat => 55.7558, lon => 37.6173, radius => 10},
{ok, Total, _Results} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
?assertEqual(1, Total),
Params2 = #{lat => 59.9343, lon => 30.3351, radius => 10},
{ok, Total2, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
?assertEqual(1, Total2).
test_combined_search() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = {{2026, 6, 15}, {10, 0, 0}},
create_test_event(CalendarId, <<"Python Workshop">>, <<"Learn Python">>, StartTime, [<<"python">>, <<"workshop">>], undefined),
create_test_event(CalendarId, <<"Python Advanced">>, <<"Advanced Python">>, {{2026, 7, 15}, {10, 0, 0}}, [<<"python">>, <<"advanced">>], undefined),
Params = #{from => {{2026, 6, 1}, {0, 0, 0}}, to => {{2026, 6, 30}, {23, 59, 59}}, tags => <<"python">>},
{ok, Total, _} = logic_search:search(<<"event">>, <<"Workshop">>, OwnerId, Params),
?assertEqual(1, Total).
test_search_calendars() ->
OwnerId = create_test_user(user),
create_test_calendar(OwnerId, personal, [<<"tech">>, <<"programming">>]),
create_test_calendar(OwnerId, commercial, [<<"yoga">>, <<"wellness">>]),
Params = #{tags => <<"tech">>},
{ok, Total, _} = logic_search:search(<<"calendar">>, undefined, OwnerId, Params),
?assertEqual(1, Total),
{ok, Total2, _} = logic_search:search(<<"calendar">>, <<"Calendar">>, OwnerId, #{}),
?assertEqual(2, Total2).
test_search_all() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
create_test_event(CalendarId, <<"Test Event">>, <<"">>, StartTime, [], undefined),
{ok, Total, Results} = logic_search:search(undefined, <<"Test">>, OwnerId, #{}),
?assert(Total >= 2),
?assert(maps:is_key(events, Results)),
?assert(maps:is_key(calendars, Results)).
test_pagination() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
lists:foreach(fun(I) ->
Title = iolist_to_binary(["Event ", integer_to_binary(I)]),
create_test_event(CalendarId, Title, <<"">>, StartTime, [], undefined)
end, [1, 2, 3, 4, 5]),
Params = #{limit => 2, offset => 0},
{ok, Total, Results} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
?assertEqual(5, Total),
?assertEqual(2, length(Results)),
Params2 = #{limit => 2, offset => 2},
{ok, _, Results2} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
?assertEqual(2, length(Results2)),
Params3 = #{limit => 2, offset => 4},
{ok, _, Results3} = logic_search:search(<<"event">>, undefined, OwnerId, Params3),
?assertEqual(1, length(Results3)).
test_sorting() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
create_test_event(CalendarId, <<"Early">>, <<"">>, {{2026, 6, 1}, {10, 0, 0}}, [], undefined),
create_test_event(CalendarId, <<"Late">>, <<"">>, {{2026, 6, 30}, {10, 0, 0}}, [], undefined),
Params = #{sort => <<"start_time">>, order => <<"asc">>},
{ok, _, [First | _]} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
?assertMatch(#{title := <<"Early">>}, First),
Params2 = #{sort => <<"start_time">>, order => <<"desc">>},
{ok, _, [First2 | _]} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
?assertMatch(#{title := <<"Late">>}, First2).
test_access_control() ->
OwnerId = create_test_user(user),
OtherId = create_test_user(user),
PersonalId = create_test_calendar(OwnerId, personal, []),
CommercialId = create_test_calendar(OwnerId, commercial, []),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
create_test_event(PersonalId, <<"Personal Event">>, <<"">>, StartTime, [], undefined),
create_test_event(CommercialId, <<"Public Event">>, <<"">>, StartTime, [], undefined),
% Другой пользователь видит только коммерческие события
{ok, Total, Results} = logic_search:search(<<"event">>, undefined, OtherId, #{}),
?assertEqual(1, Total),
[Event] = Results,
?assertMatch(#{title := <<"Public Event">>}, Event).
test_empty_search() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = {{2026, 6, 1}, {10, 0, 0}},
create_test_event(CalendarId, <<"Test">>, <<"">>, StartTime, [], undefined),
{ok, Total, Results} = logic_search:search(<<"event">>, <<"nonexistent">>, OwnerId, #{}),
?assertEqual(0, Total),
?assertEqual([], Results).