mitgliederverwaltung/test/membership/fuzzy_search_test.exs
carla 44f88f1ddd
All checks were successful
continuous-integration/drone/push Build is passing
test: aded more tests for fuzzy search
2025-11-12 11:55:48 +01:00

443 lines
11 KiB
Elixir

defmodule Mv.Membership.FuzzySearchTest do
use Mv.DataCase, async: false
test "fuzzy_search/2 function exists" do
assert function_exported?(Mv.Membership.Member, :fuzzy_search, 2)
end
test "fuzzy_search returns only John Doe by fuzzy query 'john'" do
{:ok, john} =
Mv.Membership.create_member(%{
first_name: "John",
last_name: "Doe",
email: "john.doe@example.com"
})
{:ok, _jane} =
Mv.Membership.create_member(%{
first_name: "Adriana",
last_name: "Smith",
email: "adriana.smith@example.com"
})
{:ok, alice} =
Mv.Membership.create_member(%{
first_name: "Alice",
last_name: "Johnson",
email: "alice.johnson@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{
query: "john"
})
|> Ash.read!()
assert Enum.map(result, & &1.id) == [john.id, alice.id]
end
test "fuzzy_search finds 'Thomas' when searching misspelled 'tomas'" do
{:ok, thomas} =
Mv.Membership.create_member(%{
first_name: "Thomas",
last_name: "Doe",
email: "john.doe@example.com"
})
{:ok, jane} =
Mv.Membership.create_member(%{
first_name: "Jane",
last_name: "Smith",
email: "jane.smith@example.com"
})
{:ok, _alice} =
Mv.Membership.create_member(%{
first_name: "Alice",
last_name: "Johnson",
email: "alice.johnson@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{
query: "tomas"
})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert thomas.id in ids
refute jane.id in ids
assert length(ids) >= 1
end
test "empty query returns all members" do
{:ok, a} =
Mv.Membership.create_member(%{first_name: "A", last_name: "One", email: "a1@example.com"})
{:ok, b} =
Mv.Membership.create_member(%{first_name: "B", last_name: "Two", email: "b2@example.com"})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: ""})
|> Ash.read!()
assert Enum.sort(Enum.map(result, & &1.id))
|> Enum.uniq()
|> Enum.sort()
|> Enum.all?(fn id -> id in [a.id, b.id] end)
end
test "substring numeric search matches postal_code mid-string" do
{:ok, m1} =
Mv.Membership.create_member(%{
first_name: "Num",
last_name: "One",
email: "n1@example.com",
postal_code: "12345"
})
{:ok, _m2} =
Mv.Membership.create_member(%{
first_name: "Num",
last_name: "Two",
email: "n2@example.com",
postal_code: "67890"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "345"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert m1.id in ids
end
test "substring numeric search matches house_number mid-string" do
{:ok, m1} =
Mv.Membership.create_member(%{
first_name: "Home",
last_name: "One",
email: "h1@example.com",
house_number: "A345B"
})
{:ok, _m2} =
Mv.Membership.create_member(%{
first_name: "Home",
last_name: "Two",
email: "h2@example.com",
house_number: "77"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "345"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert m1.id in ids
end
test "fuzzy matches street misspelling" do
{:ok, s1} =
Mv.Membership.create_member(%{
first_name: "Road",
last_name: "Test",
email: "s1@example.com",
street: "Main Street"
})
{:ok, _s2} =
Mv.Membership.create_member(%{
first_name: "Road",
last_name: "Other",
email: "s2@example.com",
street: "Second Avenue"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "mainn"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert s1.id in ids
end
test "substring in city matches mid-string" do
{:ok, b} =
Mv.Membership.create_member(%{
first_name: "City",
last_name: "One",
email: "city1@example.com",
city: "Berlin"
})
{:ok, _m} =
Mv.Membership.create_member(%{
first_name: "City",
last_name: "Two",
email: "city2@example.com",
city: "München"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "erl"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert b.id in ids
end
test "blank character handling: query with spaces matches full name" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "John",
last_name: "Doe",
email: "john.doe@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "Jane",
last_name: "Smith",
email: "jane.smith@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "john doe"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "blank character handling: query with multiple spaces is handled" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Mary",
last_name: "Jane",
email: "mary.jane@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "mary jane"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "special character handling: @ symbol in query matches email" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Test",
last_name: "User",
email: "test.user@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "Other",
last_name: "Person",
email: "other.person@different.org"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "example"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "special character handling: dot in query matches email" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Dot",
last_name: "Test",
email: "dot.test@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "No",
last_name: "Dot",
email: "nodot@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "dot.test"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "special character handling: hyphen in query matches data" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Mary-Jane",
last_name: "Watson",
email: "mary.jane@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "Mary",
last_name: "Smith",
email: "mary.smith@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "mary-jane"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "unicode character handling: umlaut ö in query matches data" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Jörg",
last_name: "Schmidt",
email: "joerg.schmidt@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "John",
last_name: "Smith",
email: "john.smith@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "jörg"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "unicode character handling: umlaut ä in query matches data" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Märta",
last_name: "Andersson",
email: "maerta.andersson@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "Marta",
last_name: "Johnson",
email: "marta.johnson@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "märta"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "unicode character handling: umlaut ü in query matches data" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Günther",
last_name: "Müller",
email: "guenther.mueller@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "Gunter",
last_name: "Miller",
email: "gunter.miller@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "müller"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "unicode character handling: query without umlaut matches data with umlaut" do
{:ok, member} =
Mv.Membership.create_member(%{
first_name: "Müller",
last_name: "Schmidt",
email: "mueller.schmidt@example.com"
})
{:ok, _other} =
Mv.Membership.create_member(%{
first_name: "Miller",
last_name: "Smith",
email: "miller.smith@example.com"
})
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: "muller"})
|> Ash.read!()
ids = Enum.map(result, & &1.id)
assert member.id in ids
end
test "very long search strings: handles long query without error" do
{:ok, _member} =
Mv.Membership.create_member(%{
first_name: "Test",
last_name: "User",
email: "test@example.com"
})
long_query = String.duplicate("a", 1000)
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: long_query})
|> Ash.read!()
# Should not crash, may return empty or some results
assert is_list(result)
end
test "very long search strings: handles extremely long query" do
{:ok, _member} =
Mv.Membership.create_member(%{
first_name: "Test",
last_name: "User",
email: "test@example.com"
})
very_long_query = String.duplicate("test query ", 1000)
result =
Mv.Membership.Member
|> Mv.Membership.Member.fuzzy_search(%{query: very_long_query})
|> Ash.read!()
# Should not crash, may return empty or some results
assert is_list(result)
end
end