Полный пересмотр логики поиска по email с стратегиями
Проблема: Поиск "team_x3m@" неправильно находит клиента "Наталья natulj@bk.ru" Причина: Использовался простой icontains для всех случаев Решение: Добавлена функция determine_search_strategy() которая определяет стратегию поиска на основе содержимого query: 1. email_prefix: query заканчивается на @ (например "team_x3m@") → Используется istartswith вместо icontains → Найдёт только email, начинающиеся с "team_x3m@" → НЕ найдёт "natulj@bk.ru" ✓ 2. email_domain: query начинается с @ (например "@bk") → Использует icontains для поиска по домену → Найдёт все *@bk.ru, *@bk.com и т.д. 3. email_full: query содержит обе части (например "test@bk.ru") → Поиск по полному email адресу 4. universal: query без @, 3+ символов (например "natul") → Поиск везде: по имени И по email → Это позволит найти "Наталья" и "natulj@bk.ru" 5. name_only: очень короткие запросы (1-2 символа) → Только поиск по имени (чтобы не было ложных срабатываний) Добавлены 23 unit-теста для покрытия всех сценариев: - email_prefix cases: team_x3m@, user_name@, test123@ - email_domain cases: @bk, @bk.ru, @mail.google.com - email_full cases: test@bk.ru, test@bk, user.name@mail.example.com - universal cases: natul, abc, наталь, Test123 - name_only cases: t, te, на - edge cases: пустая строка, @, множественные @ Все 23 теста проходят успешно ✓ Примеры работы после изменения: - team_x3m@ → ищет email^=team_x3m (НЕ найдёт natulj@bk.ru) - @bk → ищет все *@bk.* - natul → ищет везде (имя + email) - te → ищет только по имени (2 символа мало для email) - test@bk.ru → ищет test@bk.ru 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
160
myproject/customers/tests.py
Normal file
160
myproject/customers/tests.py
Normal file
@@ -0,0 +1,160 @@
|
||||
from django.test import TestCase
|
||||
from .views import determine_search_strategy
|
||||
|
||||
|
||||
class DetermineSearchStrategyTestCase(TestCase):
|
||||
"""
|
||||
Тесты для функции determine_search_strategy().
|
||||
|
||||
Проверяют, что функция правильно определяет стратегию поиска
|
||||
на основе содержимого query.
|
||||
"""
|
||||
|
||||
# ===== email_prefix: query заканчивается на @ =====
|
||||
def test_email_prefix_simple(self):
|
||||
"""Query "team_x3m@" должен вернуть ('email_prefix', 'team_x3m')"""
|
||||
strategy, search_value = determine_search_strategy('team_x3m@')
|
||||
self.assertEqual(strategy, 'email_prefix')
|
||||
self.assertEqual(search_value, 'team_x3m')
|
||||
|
||||
def test_email_prefix_with_domain_symbol(self):
|
||||
"""Query "user_name@" должен вернуть ('email_prefix', 'user_name')"""
|
||||
strategy, search_value = determine_search_strategy('user_name@')
|
||||
self.assertEqual(strategy, 'email_prefix')
|
||||
self.assertEqual(search_value, 'user_name')
|
||||
|
||||
def test_email_prefix_with_numbers(self):
|
||||
"""Query "test123@" должен вернуть ('email_prefix', 'test123')"""
|
||||
strategy, search_value = determine_search_strategy('test123@')
|
||||
self.assertEqual(strategy, 'email_prefix')
|
||||
self.assertEqual(search_value, 'test123')
|
||||
|
||||
# ===== email_domain: query начинается с @ =====
|
||||
def test_email_domain_simple(self):
|
||||
"""Query "@bk" должен вернуть ('email_domain', 'bk')"""
|
||||
strategy, search_value = determine_search_strategy('@bk')
|
||||
self.assertEqual(strategy, 'email_domain')
|
||||
self.assertEqual(search_value, 'bk')
|
||||
|
||||
def test_email_domain_with_extension(self):
|
||||
"""Query "@bk.ru" должен вернуть ('email_domain', 'bk.ru')"""
|
||||
strategy, search_value = determine_search_strategy('@bk.ru')
|
||||
self.assertEqual(strategy, 'email_domain')
|
||||
self.assertEqual(search_value, 'bk.ru')
|
||||
|
||||
def test_email_domain_with_multiple_dots(self):
|
||||
"""Query "@mail.google.com" должен вернуть ('email_domain', 'mail.google.com')"""
|
||||
strategy, search_value = determine_search_strategy('@mail.google.com')
|
||||
self.assertEqual(strategy, 'email_domain')
|
||||
self.assertEqual(search_value, 'mail.google.com')
|
||||
|
||||
# ===== email_full: query содержит и локальную часть, и домен =====
|
||||
def test_email_full_simple(self):
|
||||
"""Query "test@bk.ru" должен вернуть ('email_full', 'test@bk.ru')"""
|
||||
strategy, search_value = determine_search_strategy('test@bk.ru')
|
||||
self.assertEqual(strategy, 'email_full')
|
||||
self.assertEqual(search_value, 'test@bk.ru')
|
||||
|
||||
def test_email_full_partial(self):
|
||||
"""Query "test@bk" должен вернуть ('email_full', 'test@bk')"""
|
||||
strategy, search_value = determine_search_strategy('test@bk')
|
||||
self.assertEqual(strategy, 'email_full')
|
||||
self.assertEqual(search_value, 'test@bk')
|
||||
|
||||
def test_email_full_complex(self):
|
||||
"""Query "user.name@mail.example.com" должен вернуть ('email_full', ...)"""
|
||||
strategy, search_value = determine_search_strategy('user.name@mail.example.com')
|
||||
self.assertEqual(strategy, 'email_full')
|
||||
self.assertEqual(search_value, 'user.name@mail.example.com')
|
||||
|
||||
# ===== universal: query без @, 3+ символов =====
|
||||
def test_universal_three_chars(self):
|
||||
"""Query "natul" (5 символов) должен вернуть ('universal', 'natul')"""
|
||||
strategy, search_value = determine_search_strategy('natul')
|
||||
self.assertEqual(strategy, 'universal')
|
||||
self.assertEqual(search_value, 'natul')
|
||||
|
||||
def test_universal_three_chars_exact(self):
|
||||
"""Query "abc" (3 символа) должен вернуть ('universal', 'abc')"""
|
||||
strategy, search_value = determine_search_strategy('abc')
|
||||
self.assertEqual(strategy, 'universal')
|
||||
self.assertEqual(search_value, 'abc')
|
||||
|
||||
def test_universal_cyrillic(self):
|
||||
"""Query "наталь" (6 символов) должен вернуть ('universal', 'наталь')"""
|
||||
strategy, search_value = determine_search_strategy('наталь')
|
||||
self.assertEqual(strategy, 'universal')
|
||||
self.assertEqual(search_value, 'наталь')
|
||||
|
||||
def test_universal_mixed(self):
|
||||
"""Query "Test123" (7 символов) должен вернуть ('universal', 'Test123')"""
|
||||
strategy, search_value = determine_search_strategy('Test123')
|
||||
self.assertEqual(strategy, 'universal')
|
||||
self.assertEqual(search_value, 'Test123')
|
||||
|
||||
# ===== name_only: очень короткие запросы (< 3 символов без @) =====
|
||||
def test_name_only_single_char(self):
|
||||
"""Query "t" должен вернуть ('name_only', 't')"""
|
||||
strategy, search_value = determine_search_strategy('t')
|
||||
self.assertEqual(strategy, 'name_only')
|
||||
self.assertEqual(search_value, 't')
|
||||
|
||||
def test_name_only_two_chars(self):
|
||||
"""Query "te" должен вернуть ('name_only', 'te')"""
|
||||
strategy, search_value = determine_search_strategy('te')
|
||||
self.assertEqual(strategy, 'name_only')
|
||||
self.assertEqual(search_value, 'te')
|
||||
|
||||
def test_name_only_two_chars_cyrillic(self):
|
||||
"""Query "на" (2 символа) должен вернуть ('name_only', 'на')"""
|
||||
strategy, search_value = determine_search_strategy('на')
|
||||
self.assertEqual(strategy, 'name_only')
|
||||
self.assertEqual(search_value, 'на')
|
||||
|
||||
# ===== edge cases =====
|
||||
def test_empty_string(self):
|
||||
"""Query "" должен вернуть ('name_only', '')"""
|
||||
strategy, search_value = determine_search_strategy('')
|
||||
self.assertEqual(strategy, 'name_only')
|
||||
self.assertEqual(search_value, '')
|
||||
|
||||
def test_only_at_symbol(self):
|
||||
"""Query "@" должен вернуть ('email_domain', '')"""
|
||||
strategy, search_value = determine_search_strategy('@')
|
||||
self.assertEqual(strategy, 'email_domain')
|
||||
self.assertEqual(search_value, '')
|
||||
|
||||
def test_multiple_at_symbols(self):
|
||||
"""Query "test@example@com" должен обработать первый @"""
|
||||
strategy, search_value = determine_search_strategy('test@example@com')
|
||||
self.assertEqual(strategy, 'email_full')
|
||||
self.assertEqual(search_value, 'test@example@com')
|
||||
|
||||
def test_spaces_in_query(self):
|
||||
"""Query "Ivan Petrov" должен вернуть ('universal', 'Ivan Petrov')"""
|
||||
strategy, search_value = determine_search_strategy('Ivan Petrov')
|
||||
self.assertEqual(strategy, 'universal')
|
||||
self.assertEqual(search_value, 'Ivan Petrov')
|
||||
|
||||
# ===== real-world examples =====
|
||||
def test_real_world_problematic_case(self):
|
||||
"""
|
||||
Real-world case: query "team_x3m@" не должен найти "natulj@bk.ru"
|
||||
Используется email_prefix со istartswith вместо icontains
|
||||
"""
|
||||
strategy, search_value = determine_search_strategy('team_x3m@')
|
||||
self.assertEqual(strategy, 'email_prefix')
|
||||
# Важно: стратегия email_prefix, не universal или email_full
|
||||
self.assertNotEqual(strategy, 'universal')
|
||||
|
||||
def test_real_world_domain_search(self):
|
||||
"""Real-world case: query "@bk" должен найти все @bk.ru"""
|
||||
strategy, search_value = determine_search_strategy('@bk')
|
||||
self.assertEqual(strategy, 'email_domain')
|
||||
self.assertEqual(search_value, 'bk')
|
||||
|
||||
def test_real_world_name_search(self):
|
||||
"""Real-world case: query "natul" должен найти "Наталья" и "natulj@bk.ru" """
|
||||
strategy, search_value = determine_search_strategy('natul')
|
||||
self.assertEqual(strategy, 'universal')
|
||||
self.assertEqual(search_value, 'natul')
|
||||
Reference in New Issue
Block a user