""" Tests for Park managers and querysets. Following Django styleguide pattern: test______ """ import pytest from django.test import TestCase from django.utils import timezone from datetime import timedelta from apps.parks.models import Park, ParkArea, ParkReview, Company from apps.parks.managers import ( ParkQuerySet, ParkManager, ParkAreaQuerySet, ParkAreaManager, ParkReviewQuerySet, ParkReviewManager, CompanyQuerySet, CompanyManager, ) from tests.factories import ( ParkFactory, ParkAreaFactory, ParkReviewFactory, RideFactory, CoasterFactory, UserFactory, OperatorCompanyFactory, ManufacturerCompanyFactory, ) @pytest.mark.django_db class TestParkQuerySet(TestCase): """Tests for ParkQuerySet.""" def test__with_complete_stats__annotates_ride_counts(self): """Test with_complete_stats adds ride count annotations.""" park = ParkFactory() RideFactory(park=park, category="TR") RideFactory(park=park, category="TR") CoasterFactory(park=park, category="RC") result = Park.objects.with_complete_stats().get(pk=park.pk) assert result.ride_count_calculated == 3 assert result.coaster_count_calculated == 1 def test__with_complete_stats__annotates_review_stats(self): """Test with_complete_stats adds review statistics.""" park = ParkFactory() user1 = UserFactory() user2 = UserFactory() ParkReviewFactory(park=park, user=user1, is_published=True, rating=8) ParkReviewFactory(park=park, user=user2, is_published=True, rating=6) result = Park.objects.with_complete_stats().get(pk=park.pk) assert result.review_count == 2 assert result.average_rating_calculated == 7.0 def test__with_complete_stats__excludes_unpublished_reviews(self): """Test review stats exclude unpublished reviews.""" park = ParkFactory() user1 = UserFactory() user2 = UserFactory() ParkReviewFactory(park=park, user=user1, is_published=True, rating=10) ParkReviewFactory(park=park, user=user2, is_published=False, rating=2) result = Park.objects.with_complete_stats().get(pk=park.pk) assert result.review_count == 1 assert result.average_rating_calculated == 10.0 def test__optimized_for_list__returns_prefetched_data(self): """Test optimized_for_list prefetches related data.""" ParkFactory() ParkFactory() queryset = Park.objects.optimized_for_list() # Should have prefetch cache populated assert queryset.count() == 2 def test__by_operator__filters_by_operator_id(self): """Test by_operator filters parks by operator.""" operator = OperatorCompanyFactory() other_operator = OperatorCompanyFactory() park1 = ParkFactory(operator=operator) park2 = ParkFactory(operator=other_operator) result = Park.objects.by_operator(operator_id=operator.pk) assert park1 in result assert park2 not in result def test__by_property_owner__filters_by_owner_id(self): """Test by_property_owner filters parks by property owner.""" owner = OperatorCompanyFactory() park1 = ParkFactory(property_owner=owner) park2 = ParkFactory() result = Park.objects.get_queryset().by_property_owner(owner_id=owner.pk) assert park1 in result assert park2 not in result def test__with_minimum_coasters__filters_by_coaster_count(self): """Test with_minimum_coasters filters parks with enough coasters.""" park1 = ParkFactory() park2 = ParkFactory() # Add 5 coasters to park1 for _ in range(5): CoasterFactory(park=park1) # Add only 2 coasters to park2 for _ in range(2): CoasterFactory(park=park2) result = Park.objects.with_minimum_coasters(min_coasters=5) assert park1 in result assert park2 not in result def test__large_parks__filters_by_size(self): """Test large_parks filters by minimum acreage.""" large_park = ParkFactory(size_acres=200) small_park = ParkFactory(size_acres=50) result = Park.objects.large_parks(min_acres=100) assert large_park in result assert small_park not in result def test__seasonal_parks__excludes_empty_operating_season(self): """Test seasonal_parks excludes parks with empty operating_season.""" seasonal_park = ParkFactory(operating_season="Summer only") year_round_park = ParkFactory(operating_season="") result = Park.objects.get_queryset().seasonal_parks() assert seasonal_park in result assert year_round_park not in result def test__search_autocomplete__searches_by_name(self): """Test search_autocomplete searches park names.""" park1 = ParkFactory(name="Cedar Point") park2 = ParkFactory(name="Kings Island") result = list(Park.objects.get_queryset().search_autocomplete(query="Cedar")) assert park1 in result assert park2 not in result def test__search_autocomplete__limits_results(self): """Test search_autocomplete respects limit parameter.""" for i in range(15): ParkFactory(name=f"Test Park {i}") result = list(Park.objects.get_queryset().search_autocomplete(query="Test", limit=5)) assert len(result) == 5 @pytest.mark.django_db class TestParkManager(TestCase): """Tests for ParkManager.""" def test__get_queryset__returns_park_queryset(self): """Test get_queryset returns ParkQuerySet.""" queryset = Park.objects.get_queryset() assert isinstance(queryset, ParkQuerySet) def test__operating__filters_operating_parks(self): """Test operating filters for operating status.""" operating = ParkFactory(status="OPERATING") closed = ParkFactory(status="CLOSED_PERM") result = Park.objects.operating() assert operating in result assert closed not in result def test__closed__filters_closed_parks(self): """Test closed filters for closed statuses.""" operating = ParkFactory(status="OPERATING") closed_temp = ParkFactory(status="CLOSED_TEMP") closed_perm = ParkFactory(status="CLOSED_PERM") result = Park.objects.closed() assert operating not in result assert closed_temp in result assert closed_perm in result @pytest.mark.django_db class TestParkAreaQuerySet(TestCase): """Tests for ParkAreaQuerySet.""" def test__with_ride_counts__annotates_ride_count(self): """Test with_ride_counts adds ride count annotation.""" park = ParkFactory() area = ParkAreaFactory(park=park) RideFactory(park=park, park_area=area) RideFactory(park=park, park_area=area) CoasterFactory(park=park, park_area=area) result = ParkArea.objects.with_ride_counts().get(pk=area.pk) assert result.ride_count == 3 assert result.coaster_count == 1 def test__by_park__filters_by_park_id(self): """Test by_park filters areas by park.""" park1 = ParkFactory() park2 = ParkFactory() area1 = ParkAreaFactory(park=park1) area2 = ParkAreaFactory(park=park2) result = ParkArea.objects.by_park(park_id=park1.pk) assert area1 in result assert area2 not in result def test__with_rides__filters_areas_with_rides(self): """Test with_rides filters areas that have rides.""" park = ParkFactory() area_with_rides = ParkAreaFactory(park=park) area_without_rides = ParkAreaFactory(park=park) RideFactory(park=park, park_area=area_with_rides) result = ParkArea.objects.get_queryset().with_rides() assert area_with_rides in result assert area_without_rides not in result @pytest.mark.django_db class TestParkReviewQuerySet(TestCase): """Tests for ParkReviewQuerySet.""" def test__for_park__filters_by_park_id(self): """Test for_park filters reviews by park.""" park1 = ParkFactory() park2 = ParkFactory() user = UserFactory() review1 = ParkReviewFactory(park=park1, user=user) user2 = UserFactory() review2 = ParkReviewFactory(park=park2, user=user2) result = ParkReview.objects.for_park(park_id=park1.pk) assert review1 in result assert review2 not in result def test__by_user__filters_by_user_id(self): """Test by_user filters reviews by user.""" user1 = UserFactory() user2 = UserFactory() review1 = ParkReviewFactory(user=user1) review2 = ParkReviewFactory(user=user2) result = ParkReview.objects.get_queryset().by_user(user_id=user1.pk) assert review1 in result assert review2 not in result def test__by_rating_range__filters_by_rating(self): """Test by_rating_range filters reviews by rating range.""" user1 = UserFactory() user2 = UserFactory() user3 = UserFactory() high_review = ParkReviewFactory(rating=9, user=user1) mid_review = ParkReviewFactory(rating=5, user=user2) low_review = ParkReviewFactory(rating=2, user=user3) result = ParkReview.objects.by_rating_range(min_rating=7, max_rating=10) assert high_review in result assert mid_review not in result assert low_review not in result def test__moderation_required__filters_unpublished_or_unmoderated(self): """Test moderation_required filters reviews needing moderation.""" user1 = UserFactory() user2 = UserFactory() published = ParkReviewFactory(is_published=True, user=user1) unpublished = ParkReviewFactory(is_published=False, user=user2) result = ParkReview.objects.moderation_required() # unpublished should definitely be in result assert unpublished in result @pytest.mark.django_db class TestCompanyQuerySet(TestCase): """Tests for CompanyQuerySet.""" def test__operators__filters_operator_companies(self): """Test operators filters for companies with OPERATOR role.""" operator = OperatorCompanyFactory() manufacturer = ManufacturerCompanyFactory() result = Company.objects.operators() assert operator in result assert manufacturer not in result def test__manufacturers__filters_manufacturer_companies(self): """Test manufacturers filters for companies with MANUFACTURER role.""" operator = OperatorCompanyFactory() manufacturer = ManufacturerCompanyFactory() result = Company.objects.manufacturers() assert manufacturer in result assert operator not in result def test__with_park_counts__annotates_park_counts(self): """Test with_park_counts adds park count annotations.""" operator = OperatorCompanyFactory() ParkFactory(operator=operator) ParkFactory(operator=operator) ParkFactory(property_owner=operator) result = Company.objects.get_queryset().with_park_counts().get(pk=operator.pk) assert result.operated_parks_count == 2 assert result.owned_parks_count == 1 def test__major_operators__filters_by_minimum_parks(self): """Test major_operators filters by minimum park count.""" major_operator = OperatorCompanyFactory() small_operator = OperatorCompanyFactory() for _ in range(6): ParkFactory(operator=major_operator) for _ in range(2): ParkFactory(operator=small_operator) result = Company.objects.major_operators(min_parks=5) assert major_operator in result assert small_operator not in result @pytest.mark.django_db class TestCompanyManager(TestCase): """Tests for CompanyManager.""" def test__manufacturers_with_ride_count__annotates_ride_count(self): """Test manufacturers_with_ride_count adds ride count annotation.""" manufacturer = ManufacturerCompanyFactory() RideFactory(manufacturer=manufacturer) RideFactory(manufacturer=manufacturer) RideFactory(manufacturer=manufacturer) result = list(Company.objects.manufacturers_with_ride_count()) mfr = next((c for c in result if c.pk == manufacturer.pk), None) assert mfr is not None assert mfr.ride_count == 3 def test__operators_with_park_count__annotates_park_count(self): """Test operators_with_park_count adds park count annotation.""" operator = OperatorCompanyFactory() ParkFactory(operator=operator) ParkFactory(operator=operator) result = list(Company.objects.operators_with_park_count()) op = next((c for c in result if c.pk == operator.pk), None) assert op is not None assert op.operated_parks_count == 2