Files
octopus/myproject/customers/tests.py
Andrey Smakotin 9fc0af2c2e Полный пересмотр логики поиска по 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>
2025-11-11 00:49:43 +03:00

161 lines
7.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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')