from django.test import TestCase, RequestFactory from django.contrib.auth.models import User from django.contrib.gis.geos import Point from .models import CustomUser, Geo, ObjItem from .utils import format_coordinates, parse_pagination_params from .mixins import RoleRequiredMixin, CoordinateProcessingMixin from django.views import View class FormatCoordinatesTestCase(TestCase): """Тесты для функции format_coordinates""" def test_format_positive_coordinates(self): """Тест форматирования положительных координат""" result = format_coordinates(37.62, 55.75) self.assertEqual(result, "55.75N 37.62E") def test_format_negative_longitude(self): """Тест форматирования с отрицательной долготой""" result = format_coordinates(-122.42, 37.77) self.assertEqual(result, "37.77N 122.42W") def test_format_negative_latitude(self): """Тест форматирования с отрицательной широтой""" result = format_coordinates(151.21, -33.87) self.assertEqual(result, "33.87S 151.21E") def test_format_both_negative(self): """Тест форматирования с обеими отрицательными координатами""" result = format_coordinates(-58.38, -34.60) self.assertEqual(result, "34.6S 58.38W") class ParsePaginationParamsTestCase(TestCase): """Тесты для функции parse_pagination_params""" def setUp(self): self.factory = RequestFactory() def test_default_values(self): """Тест значений по умолчанию""" request = self.factory.get("/") page, per_page = parse_pagination_params(request) self.assertEqual(page, 1) self.assertEqual(per_page, 50) def test_custom_values(self): """Тест пользовательских значений""" request = self.factory.get("/?page=3&items_per_page=100") page, per_page = parse_pagination_params(request) self.assertEqual(page, 3) self.assertEqual(per_page, 100) def test_invalid_page_number(self): """Тест невалидного номера страницы""" request = self.factory.get("/?page=invalid") page, per_page = parse_pagination_params(request) self.assertEqual(page, 1) def test_negative_page_number(self): """Тест отрицательного номера страницы""" request = self.factory.get("/?page=-5") page, per_page = parse_pagination_params(request) self.assertEqual(page, 1) def test_max_items_per_page_limit(self): """Тест ограничения максимального количества элементов""" request = self.factory.get("/?items_per_page=20000") page, per_page = parse_pagination_params(request) self.assertEqual(per_page, 10000) class RoleRequiredMixinTestCase(TestCase): """Тесты для RoleRequiredMixin""" def setUp(self): self.factory = RequestFactory() def test_admin_has_access(self): """Тест что администратор имеет доступ""" user = User.objects.create_user(username="testuser", password="12345") # Get the automatically created CustomUser and set role to 'admin' custom_user = CustomUser.objects.get(user=user) custom_user.role = "admin" custom_user.save() # Refresh user to get updated customuser user.refresh_from_db() class TestView(RoleRequiredMixin, View): required_roles = ["admin", "moderator"] view = TestView() request = self.factory.get("/") request.user = user view.request = request self.assertTrue(view.test_func()) def test_user_without_role_denied(self): """Тест что пользователь без роли не имеет доступа""" user_no_role = User.objects.create_user(username="norole", password="12345") # Get the automatically created CustomUser - default role is 'user' custom_user_no_role = CustomUser.objects.get(user=user_no_role) self.assertEqual(custom_user_no_role.role, "user") class TestView(RoleRequiredMixin, View): required_roles = ["admin", "moderator"] view = TestView() request = self.factory.get("/") request.user = user_no_role view.request = request self.assertFalse(view.test_func()) class CoordinateProcessingMixinTestCase(TestCase): """Тесты для CoordinateProcessingMixin""" def setUp(self): self.factory = RequestFactory() def test_extract_geo_coordinates(self): """Тест извлечения координат геолокации""" class TestView(CoordinateProcessingMixin, View): pass view = TestView() request = self.factory.post( "/", {"geo_longitude": "37.62", "geo_latitude": "55.75"} ) view.request = request coords = view._extract_coordinates("geo") self.assertIsNotNone(coords) self.assertEqual(coords, (37.62, 55.75)) def test_extract_invalid_coordinates(self): """Тест извлечения невалидных координат""" class TestView(CoordinateProcessingMixin, View): pass view = TestView() request = self.factory.post( "/", {"geo_longitude": "invalid", "geo_latitude": "55.75"} ) view.request = request coords = view._extract_coordinates("geo") self.assertIsNone(coords) def test_process_coordinates(self): """Тест обработки координат и применения к объекту Geo""" class TestView(CoordinateProcessingMixin, View): pass view = TestView() request = self.factory.post( "/", { "geo_longitude": "37.62", "geo_latitude": "55.75", }, ) view.request = request geo_instance = Geo() view.process_coordinates(geo_instance) self.assertIsNotNone(geo_instance.coords) self.assertEqual(geo_instance.coords.coords, (37.62, 55.75)) class CSVImportTestCase(TestCase): """Тесты для функции get_points_from_csv""" def setUp(self): """Подготовка тестовых данных""" from .models import CustomUser, Satellite, Polarization from django.contrib.auth.models import User # Создаем пользователя user = User.objects.create_user(username="testuser", password="12345") self.custom_user = CustomUser.objects.get(user=user) # Создаем спутник self.satellite = Satellite.objects.create(name="Test Satellite", norad=12345) # Создаем поляризации Polarization.objects.get_or_create(name="Вертикальная") Polarization.objects.get_or_create(name="Горизонтальная") Polarization.objects.get_or_create(name="Правая") Polarization.objects.get_or_create(name="Левая") Polarization.objects.get_or_create(name="-") # Создаем спутники-зеркала для тестов Satellite.objects.get_or_create(name="Mirror1 Satellite", norad=11111) Satellite.objects.get_or_create(name="Mirror2 Satellite", norad=22222) Satellite.objects.get_or_create(name="Mirror3 Satellite", norad=33333) def test_initial_csv_import(self): """Тест первичного импорта из CSV файла""" from .utils import get_points_from_csv from .models import Source, ObjItem # Тестовые данные CSV - 3 точки в разных местах csv_content = """1;Signal1 V;55.7558;37.6173;0;01.01.2024 12:00:00;Test Satellite;12345;11500.5;36.0;1;good;Mirror1;Mirror2;Mirror3 2;Signal2 H;55.7560;37.6175;0;01.01.2024 12:05:00;Test Satellite;12345;11520.3;36.0;1;good;Mirror1;Mirror2; 3;Signal3 V;56.8389;60.6057;0;01.01.2024 12:10:00;Test Satellite;12345;11540.7;36.0;1;good;Mirror1;Mirror2;""" # Выполняем импорт sources_created = get_points_from_csv(csv_content, self.custom_user) # Проверяем результаты # Первые две точки близко (Москва), третья далеко (Екатеринбург) # Должно быть создано 2 источника self.assertEqual(sources_created, 2) self.assertEqual(Source.objects.count(), 2) self.assertEqual(ObjItem.objects.count(), 3) # Проверяем, что первые две точки привязаны к одному источнику source1 = Source.objects.first() items_in_source1 = ObjItem.objects.filter(source=source1).count() self.assertEqual(items_in_source1, 2) def test_csv_import_with_existing_sources(self): """Тест импорта CSV с существующими источниками""" from .utils import get_points_from_csv from .models import Source, ObjItem # Первый импорт - создаем начальные данные csv_content_1 = """1;Signal1 V;55.7558;37.6173;0;01.01.2024 12:00:00;Test Satellite;12345;11500.5;36.0;1;good;Mirror1;Mirror2; 2;Signal2 H;55.7560;37.6175;0;01.01.2024 12:05:00;Test Satellite;12345;11520.3;36.0;1;good;Mirror1;Mirror2;""" sources_created_1 = get_points_from_csv(csv_content_1, self.custom_user) self.assertEqual(sources_created_1, 1) initial_sources_count = Source.objects.count() initial_objitems_count = ObjItem.objects.count() # Второй импорт - добавляем новые точки # Точка 3 - близко к существующему источнику (Москва) # Точка 4 - далеко (Екатеринбург) - создаст новый источник csv_content_2 = """3;Signal3 V;55.7562;37.6177;0;01.01.2024 12:10:00;Test Satellite;12345;11540.7;36.0;1;good;Mirror1;Mirror2; 4;Signal4 H;56.8389;60.6057;0;01.01.2024 12:15:00;Test Satellite;12345;11560.2;36.0;1;good;Mirror1;Mirror2;""" sources_created_2 = get_points_from_csv(csv_content_2, self.custom_user) # Проверяем результаты # Должен быть создан 1 новый источник (для точки 4) self.assertEqual(sources_created_2, 1) self.assertEqual(Source.objects.count(), initial_sources_count + 1) self.assertEqual(ObjItem.objects.count(), initial_objitems_count + 2) # Проверяем, что точка 3 добавлена к существующему источнику first_source = Source.objects.first() items_in_first_source = ObjItem.objects.filter(source=first_source).count() self.assertEqual(items_in_first_source, 3) # 2 начальных + 1 новая def test_csv_import_skip_duplicates(self): """Тест пропуска дубликатов при импорте CSV""" from .utils import get_points_from_csv from .models import Source, ObjItem # Первый импорт csv_content_1 = """1;Signal1 V;55.7558;37.6173;0;01.01.2024 12:00:00;Test Satellite;12345;11500.5;36.0;1;good;Mirror1;Mirror2;""" get_points_from_csv(csv_content_1, self.custom_user) initial_sources_count = Source.objects.count() initial_objitems_count = ObjItem.objects.count() # Второй импорт - та же точка (дубликат) csv_content_2 = """1;Signal1 V;55.7558;37.6173;0;01.01.2024 12:00:00;Test Satellite;12345;11500.5;36.0;1;good;Mirror1;Mirror2;""" sources_created = get_points_from_csv(csv_content_2, self.custom_user) # Проверяем, что дубликат пропущен self.assertEqual(sources_created, 0) self.assertEqual(Source.objects.count(), initial_sources_count) self.assertEqual(ObjItem.objects.count(), initial_objitems_count) def test_csv_import_mixed_scenario(self): """Тест смешанного сценария: дубликаты + новые точки + близкие точки""" from .utils import get_points_from_csv from .models import Source, ObjItem # Первый импорт - 2 точки в Москве csv_content_1 = """1;Signal1 V;55.7558;37.6173;0;01.01.2024 12:00:00;Test Satellite;12345;11500.5;36.0;1;good;Mirror1;Mirror2; 2;Signal2 H;55.7560;37.6175;0;01.01.2024 12:05:00;Test Satellite;12345;11520.3;36.0;1;good;Mirror1;Mirror2;""" get_points_from_csv(csv_content_1, self.custom_user) # Второй импорт: # - Точка 1 (дубликат) - должна быть пропущена # - Точка 3 (близко к Москве) - должна добавиться к существующему источнику # - Точка 4 (Екатеринбург) - должна создать новый источник # - Точка 5 (близко к Екатеринбургу) - должна добавиться к новому источнику csv_content_2 = """1;Signal1 V;55.7558;37.6173;0;01.01.2024 12:00:00;Test Satellite;12345;11500.5;36.0;1;good;Mirror1;Mirror2; 3;Signal3 V;55.7562;37.6177;0;01.01.2024 12:10:00;Test Satellite;12345;11540.7;36.0;1;good;Mirror1;Mirror2; 4;Signal4 H;56.8389;60.6057;0;01.01.2024 12:15:00;Test Satellite;12345;11560.2;36.0;1;good;Mirror1;Mirror2; 5;Signal5 V;56.8391;60.6059;0;01.01.2024 12:20:00;Test Satellite;12345;11580.8;36.0;1;good;Mirror1;Mirror2;""" sources_created = get_points_from_csv(csv_content_2, self.custom_user) # Проверяем результаты self.assertEqual(sources_created, 1) # Только для Екатеринбурга self.assertEqual(Source.objects.count(), 2) # Москва + Екатеринбург self.assertEqual(ObjItem.objects.count(), 5) # 2 начальных + 3 новых (дубликат пропущен) # Проверяем распределение по источникам moscow_source = Source.objects.first() ekb_source = Source.objects.last() moscow_items = ObjItem.objects.filter(source=moscow_source).count() ekb_items = ObjItem.objects.filter(source=ekb_source).count() self.assertEqual(moscow_items, 3) # 2 начальных + 1 новая self.assertEqual(ekb_items, 2) # 2 новых точки в Екатеринбурге class FindMirrorSatellitesTestCase(TestCase): """Тесты для функции find_mirror_satellites""" def setUp(self): """Подготовка тестовых данных""" from .models import Satellite # Создаем спутники с разными именами Satellite.objects.create(name="Eutelsat 16A", norad=40874) Satellite.objects.create(name="Eutelsat 21B", norad=41591) Satellite.objects.create(name="Astra 4A", norad=41404) Satellite.objects.create(name="Turksat 4A", norad=40361) Satellite.objects.create(name="Express AM6", norad=39508) def test_find_exact_match(self): """Тест поиска спутника по точному совпадению""" from .utils import find_mirror_satellites mirrors = find_mirror_satellites(["Eutelsat 16A"]) self.assertEqual(len(mirrors), 1) self.assertEqual(mirrors[0].name, "Eutelsat 16A") def test_find_partial_match(self): """Тест поиска спутника по частичному совпадению""" from .utils import find_mirror_satellites # Ищем по части имени "Eutelsat" mirrors = find_mirror_satellites(["eutelsat"]) self.assertEqual(len(mirrors), 2) names = [m.name for m in mirrors] self.assertIn("Eutelsat 16A", names) self.assertIn("Eutelsat 21B", names) def test_find_case_insensitive(self): """Тест поиска без учета регистра""" from .utils import find_mirror_satellites # Разные варианты регистра mirrors1 = find_mirror_satellites(["ASTRA"]) mirrors2 = find_mirror_satellites(["astra"]) mirrors3 = find_mirror_satellites(["AsTrA"]) self.assertEqual(len(mirrors1), 1) self.assertEqual(len(mirrors2), 1) self.assertEqual(len(mirrors3), 1) self.assertEqual(mirrors1[0].name, "Astra 4A") self.assertEqual(mirrors2[0].name, "Astra 4A") self.assertEqual(mirrors3[0].name, "Astra 4A") def test_find_multiple_mirrors(self): """Тест поиска нескольких зеркал""" from .utils import find_mirror_satellites mirrors = find_mirror_satellites(["Eutelsat", "Turksat"]) self.assertEqual(len(mirrors), 3) # 2 Eutelsat + 1 Turksat names = [m.name for m in mirrors] self.assertIn("Eutelsat 16A", names) self.assertIn("Eutelsat 21B", names) self.assertIn("Turksat 4A", names) def test_find_with_spaces(self): """Тест поиска с пробелами в начале и конце""" from .utils import find_mirror_satellites mirrors = find_mirror_satellites([" Express "]) self.assertEqual(len(mirrors), 1) self.assertEqual(mirrors[0].name, "Express AM6") def test_find_empty_list(self): """Тест с пустым списком""" from .utils import find_mirror_satellites mirrors = find_mirror_satellites([]) self.assertEqual(len(mirrors), 0) def test_find_with_dash(self): """Тест с дефисом (должен быть пропущен)""" from .utils import find_mirror_satellites mirrors = find_mirror_satellites(["-"]) self.assertEqual(len(mirrors), 0) def test_find_no_match(self): """Тест когда спутник не найден""" from .utils import find_mirror_satellites mirrors = find_mirror_satellites(["NonExistentSatellite"]) self.assertEqual(len(mirrors), 0) def test_find_removes_duplicates(self): """Тест удаления дубликатов""" from .utils import find_mirror_satellites # Ищем один и тот же спутник дважды mirrors = find_mirror_satellites(["Astra", "Astra 4A"]) self.assertEqual(len(mirrors), 1) self.assertEqual(mirrors[0].name, "Astra 4A")