mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-21 17:31:08 -05:00
Integrate parks app with site-wide search system; add filter configuration, error handling, and search interfaces
This commit is contained in:
1
parks/tests/__init__.py
Normal file
1
parks/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Parks app test suite
|
||||
250
parks/tests/test_filters.py
Normal file
250
parks/tests/test_filters.py
Normal file
@@ -0,0 +1,250 @@
|
||||
"""
|
||||
Tests for park filtering functionality including search, status filtering,
|
||||
date ranges, and numeric validations.
|
||||
"""
|
||||
from django.test import TestCase
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import timezone
|
||||
from datetime import date, timedelta
|
||||
|
||||
from parks.models import Park
|
||||
from parks.filters import ParkFilter
|
||||
from companies.models import Company
|
||||
from location.models import Location
|
||||
|
||||
class ParkFilterTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
"""Set up test data for all filter tests"""
|
||||
# Create companies
|
||||
cls.company1 = Company.objects.create(
|
||||
name="Thrilling Adventures Inc",
|
||||
slug="thrilling-adventures"
|
||||
)
|
||||
cls.company2 = Company.objects.create(
|
||||
name="Family Fun Corp",
|
||||
slug="family-fun"
|
||||
)
|
||||
|
||||
# Create parks with various attributes for testing all filters
|
||||
cls.park1 = Park.objects.create(
|
||||
name="Thrilling Adventures Park",
|
||||
description="A thrilling park with lots of roller coasters",
|
||||
status="OPERATING",
|
||||
owner=cls.company1,
|
||||
opening_date=date(2020, 1, 1),
|
||||
size_acres=100,
|
||||
ride_count=20,
|
||||
coaster_count=5,
|
||||
average_rating=4.5
|
||||
)
|
||||
Location.objects.create(
|
||||
name="Thrilling Adventures Location",
|
||||
location_type="park",
|
||||
street_address="123 Thrill St",
|
||||
city="Thrill City",
|
||||
state="Thrill State",
|
||||
country="USA",
|
||||
postal_code="12345",
|
||||
latitude=40.7128,
|
||||
longitude=-74.0060,
|
||||
content_object=cls.park1
|
||||
)
|
||||
|
||||
cls.park2 = Park.objects.create(
|
||||
name="Family Fun Park",
|
||||
description="Family-friendly entertainment and attractions",
|
||||
status="CLOSED_TEMP",
|
||||
owner=cls.company2,
|
||||
opening_date=date(2015, 6, 15),
|
||||
size_acres=50,
|
||||
ride_count=15,
|
||||
coaster_count=2,
|
||||
average_rating=4.0
|
||||
)
|
||||
Location.objects.create(
|
||||
name="Family Fun Location",
|
||||
location_type="park",
|
||||
street_address="456 Fun St",
|
||||
city="Fun City",
|
||||
state="Fun State",
|
||||
country="Canada",
|
||||
postal_code="54321",
|
||||
latitude=43.6532,
|
||||
longitude=-79.3832,
|
||||
content_object=cls.park2
|
||||
)
|
||||
|
||||
# Park with minimal data for edge case testing
|
||||
cls.park3 = Park.objects.create(
|
||||
name="Incomplete Park",
|
||||
status="UNDER_CONSTRUCTION"
|
||||
)
|
||||
|
||||
def test_text_search(self):
|
||||
"""Test search functionality across different fields"""
|
||||
# Test name search
|
||||
queryset = ParkFilter(data={"search": "Thrilling"}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park1, queryset)
|
||||
|
||||
# Test description search
|
||||
queryset = ParkFilter(data={"search": "family-friendly"}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park2, queryset)
|
||||
|
||||
# Test location search
|
||||
queryset = ParkFilter(data={"search": "Thrill City"}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park1, queryset)
|
||||
|
||||
# Test combined field search
|
||||
queryset = ParkFilter(data={"search": "Park"}).qs
|
||||
self.assertEqual(queryset.count(), 3)
|
||||
|
||||
# Test empty search
|
||||
queryset = ParkFilter(data={}).qs
|
||||
self.assertEqual(queryset.count(), 3)
|
||||
def test_status_filtering(self):
|
||||
"""Test status filter with various values"""
|
||||
# Test each status
|
||||
status_tests = {
|
||||
"OPERATING": [self.park1],
|
||||
"CLOSED_TEMP": [self.park2],
|
||||
"UNDER_CONSTRUCTION": [self.park3]
|
||||
}
|
||||
|
||||
for status, expected_parks in status_tests.items():
|
||||
queryset = ParkFilter(data={"status": status}).qs
|
||||
self.assertEqual(queryset.count(), len(expected_parks))
|
||||
for park in expected_parks:
|
||||
self.assertIn(park, queryset)
|
||||
|
||||
# Test empty status (should return all)
|
||||
queryset = ParkFilter(data={}).qs
|
||||
self.assertEqual(queryset.count(), 3)
|
||||
|
||||
# Test invalid status
|
||||
queryset = ParkFilter(data={"status": "INVALID"}).qs
|
||||
self.assertEqual(queryset.count(), 0)
|
||||
self.assertEqual(queryset.count(), 3)
|
||||
|
||||
def test_date_range_filtering(self):
|
||||
"""Test date range filter functionality"""
|
||||
# Test various date range scenarios
|
||||
test_cases = [
|
||||
# Start date only
|
||||
({
|
||||
"opening_date_after": "2019-01-01"
|
||||
}, [self.park1]),
|
||||
|
||||
# End date only
|
||||
({
|
||||
"opening_date_before": "2016-01-01"
|
||||
}, [self.park2]),
|
||||
|
||||
# Date range including one park
|
||||
({
|
||||
"opening_date_after": "2014-01-01",
|
||||
"opening_date_before": "2016-01-01"
|
||||
}, [self.park2]),
|
||||
|
||||
# Date range including multiple parks
|
||||
({
|
||||
"opening_date_after": "2014-01-01",
|
||||
"opening_date_before": "2022-01-01"
|
||||
}, [self.park1, self.park2]),
|
||||
|
||||
# Empty filter (should return all)
|
||||
({}, [self.park1, self.park2, self.park3]),
|
||||
|
||||
# Future date (should return none)
|
||||
({
|
||||
"opening_date_after": "2030-01-01"
|
||||
}, []),
|
||||
]
|
||||
|
||||
for filter_data, expected_parks in test_cases:
|
||||
queryset = ParkFilter(data=filter_data).qs
|
||||
self.assertEqual(
|
||||
set(queryset),
|
||||
set(expected_parks),
|
||||
f"Failed for filter: {filter_data}"
|
||||
)
|
||||
|
||||
# Test invalid date formats
|
||||
invalid_dates = [
|
||||
{"opening_date_after": "invalid-date"},
|
||||
{"opening_date_before": "2023-13-01"}, # Invalid month
|
||||
{"opening_date_after": "2023-01-32"}, # Invalid day
|
||||
{"opening_date_before": "not-a-date"},
|
||||
]
|
||||
|
||||
for invalid_data in invalid_dates:
|
||||
filter_instance = ParkFilter(data=invalid_data)
|
||||
self.assertFalse(
|
||||
filter_instance.is_valid(),
|
||||
f"Filter should be invalid for data: {invalid_data}"
|
||||
)
|
||||
|
||||
def test_company_filtering(self):
|
||||
"""Test company/owner filtering"""
|
||||
# Test specific company
|
||||
queryset = ParkFilter(data={"owner": str(self.company1.id)}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park1, queryset)
|
||||
|
||||
# Test other company
|
||||
queryset = ParkFilter(data={"owner": str(self.company2.id)}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park2, queryset)
|
||||
|
||||
# Test null owner (park3 has no owner)
|
||||
queryset = ParkFilter(data={"owner": "null"}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park3, queryset)
|
||||
|
||||
# Test empty filter (should return all)
|
||||
queryset = ParkFilter(data={}).qs
|
||||
self.assertEqual(queryset.count(), 3)
|
||||
|
||||
# Test invalid company ID
|
||||
queryset = ParkFilter(data={"owner": "99999"}).qs
|
||||
self.assertEqual(queryset.count(), 0)
|
||||
|
||||
def test_numeric_filtering(self):
|
||||
"""Test numeric filters with validation"""
|
||||
# Test minimum rides filter
|
||||
test_cases = [
|
||||
({"min_rides": "18"}, [self.park1]), # Only park1 has >= 18 rides
|
||||
({"min_rides": "10"}, [self.park1, self.park2]), # Both park1 and park2 have >= 10 rides
|
||||
({"min_rides": "0"}, [self.park1, self.park2, self.park3]), # All parks have >= 0 rides
|
||||
({}, [self.park1, self.park2, self.park3]), # No filter should return all
|
||||
]
|
||||
|
||||
for filter_data, expected_parks in test_cases:
|
||||
queryset = ParkFilter(data=filter_data).qs
|
||||
self.assertEqual(
|
||||
set(queryset),
|
||||
set(expected_parks),
|
||||
f"Failed for filter: {filter_data}"
|
||||
)
|
||||
|
||||
# Test coaster count filter
|
||||
queryset = ParkFilter(data={"min_coasters": "3"}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park1, queryset)
|
||||
|
||||
# Test size filter
|
||||
queryset = ParkFilter(data={"min_size": "75"}).qs
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
self.assertIn(self.park1, queryset)
|
||||
|
||||
# Test validation
|
||||
invalid_values = ["-1", "invalid", "0.5"]
|
||||
for value in invalid_values:
|
||||
filter_instance = ParkFilter(data={"min_rides": value})
|
||||
self.assertFalse(
|
||||
filter_instance.is_valid(),
|
||||
f"Filter should be invalid for value: {value}"
|
||||
)
|
||||
213
parks/tests/test_models.py
Normal file
213
parks/tests/test_models.py
Normal file
@@ -0,0 +1,213 @@
|
||||
"""
|
||||
Tests for park models functionality including CRUD operations,
|
||||
slug handling, status management, and location integration.
|
||||
"""
|
||||
from django.test import TestCase
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
from datetime import date
|
||||
|
||||
from parks.models import Park, ParkArea
|
||||
from companies.models import Company
|
||||
from location.models import Location
|
||||
|
||||
class ParkModelTests(TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test data"""
|
||||
self.company = Company.objects.create(
|
||||
name="Test Company",
|
||||
slug="test-company"
|
||||
)
|
||||
|
||||
# Create a basic park
|
||||
self.park = Park.objects.create(
|
||||
name="Test Park",
|
||||
description="A test park",
|
||||
status="OPERATING",
|
||||
owner=self.company
|
||||
)
|
||||
|
||||
# Create location for the park
|
||||
self.location = Location.objects.create(
|
||||
name="Test Park Location",
|
||||
location_type="park",
|
||||
street_address="123 Test St",
|
||||
city="Test City",
|
||||
state="Test State",
|
||||
country="Test Country",
|
||||
postal_code="12345",
|
||||
latitude=40.7128,
|
||||
longitude=-74.0060,
|
||||
content_object=self.park
|
||||
)
|
||||
|
||||
def test_park_creation(self):
|
||||
"""Test basic park creation and fields"""
|
||||
self.assertEqual(self.park.name, "Test Park")
|
||||
self.assertEqual(self.park.slug, "test-park")
|
||||
self.assertEqual(self.park.status, "OPERATING")
|
||||
self.assertEqual(self.park.owner, self.company)
|
||||
|
||||
def test_slug_generation(self):
|
||||
"""Test automatic slug generation"""
|
||||
park = Park.objects.create(
|
||||
name="Another Test Park",
|
||||
status="OPERATING"
|
||||
)
|
||||
self.assertEqual(park.slug, "another-test-park")
|
||||
|
||||
def test_historical_slug_lookup(self):
|
||||
"""Test finding park by historical slug"""
|
||||
from django.db import transaction
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from history_tracking.models import HistoricalSlug
|
||||
|
||||
with transaction.atomic():
|
||||
# Create initial park with a specific name/slug
|
||||
park = Park.objects.create(
|
||||
name="Original Park Name",
|
||||
description="Test description",
|
||||
status="OPERATING"
|
||||
)
|
||||
original_slug = park.slug
|
||||
print(f"\nInitial park created with slug: {original_slug}")
|
||||
|
||||
# Ensure we have a save to trigger history
|
||||
park.save()
|
||||
|
||||
# Modify name to trigger slug change
|
||||
park.name = "Updated Park Name"
|
||||
park.save()
|
||||
new_slug = park.slug
|
||||
print(f"Park updated with new slug: {new_slug}")
|
||||
|
||||
# Check HistoricalSlug records
|
||||
historical_slugs = HistoricalSlug.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(Park),
|
||||
object_id=park.id
|
||||
)
|
||||
print(f"Historical slug records: {[h.slug for h in historical_slugs]}")
|
||||
|
||||
# Check pghistory records
|
||||
event_model = getattr(Park, 'event_model', None)
|
||||
if event_model:
|
||||
historical_records = event_model.objects.filter(
|
||||
pgh_obj_id=park.id
|
||||
).order_by('-pgh_created_at')
|
||||
print(f"\nPG History records:")
|
||||
for record in historical_records:
|
||||
print(f"- Event ID: {record.pgh_id}")
|
||||
print(f" Name: {record.name}")
|
||||
print(f" Slug: {record.slug}")
|
||||
print(f" Created At: {record.pgh_created_at}")
|
||||
else:
|
||||
print("\nNo pghistory event model available")
|
||||
|
||||
# Try to find by old slug
|
||||
found_park, is_historical = Park.get_by_slug(original_slug)
|
||||
self.assertEqual(found_park.id, park.id)
|
||||
print(f"Found park by old slug: {found_park.slug}, is_historical: {is_historical}")
|
||||
self.assertTrue(is_historical)
|
||||
|
||||
# Try current slug
|
||||
found_park, is_historical = Park.get_by_slug(new_slug)
|
||||
self.assertEqual(found_park.id, park.id)
|
||||
print(f"Found park by new slug: {found_park.slug}, is_historical: {is_historical}")
|
||||
self.assertFalse(is_historical)
|
||||
|
||||
def test_status_color_mapping(self):
|
||||
"""Test status color class mapping"""
|
||||
status_tests = {
|
||||
'OPERATING': 'bg-green-100 text-green-800',
|
||||
'CLOSED_TEMP': 'bg-yellow-100 text-yellow-800',
|
||||
'CLOSED_PERM': 'bg-red-100 text-red-800',
|
||||
'UNDER_CONSTRUCTION': 'bg-blue-100 text-blue-800',
|
||||
'DEMOLISHED': 'bg-gray-100 text-gray-800',
|
||||
'RELOCATED': 'bg-purple-100 text-purple-800'
|
||||
}
|
||||
|
||||
for status, expected_color in status_tests.items():
|
||||
self.park.status = status
|
||||
self.assertEqual(self.park.get_status_color(), expected_color)
|
||||
|
||||
def test_location_integration(self):
|
||||
"""Test location-related functionality"""
|
||||
# Test formatted location - compare individual components
|
||||
location = self.park.location.first()
|
||||
self.assertIsNotNone(location)
|
||||
formatted_address = location.get_formatted_address()
|
||||
self.assertIn("123 Test St", formatted_address)
|
||||
self.assertIn("Test City", formatted_address)
|
||||
self.assertIn("Test State", formatted_address)
|
||||
self.assertIn("12345", formatted_address)
|
||||
self.assertIn("Test Country", formatted_address)
|
||||
|
||||
# Test coordinates
|
||||
self.assertEqual(self.park.coordinates, (40.7128, -74.0060))
|
||||
|
||||
# Test park without location
|
||||
park = Park.objects.create(name="No Location Park")
|
||||
self.assertEqual(park.formatted_location, "")
|
||||
self.assertIsNone(park.coordinates)
|
||||
|
||||
def test_absolute_url(self):
|
||||
"""Test get_absolute_url method"""
|
||||
expected_url = f"/parks/{self.park.slug}/"
|
||||
self.assertEqual(self.park.get_absolute_url(), expected_url)
|
||||
|
||||
class ParkAreaModelTests(TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test data"""
|
||||
self.park = Park.objects.create(
|
||||
name="Test Park",
|
||||
status="OPERATING"
|
||||
)
|
||||
self.area = ParkArea.objects.create(
|
||||
park=self.park,
|
||||
name="Test Area",
|
||||
description="A test area"
|
||||
)
|
||||
|
||||
def test_area_creation(self):
|
||||
"""Test basic area creation and fields"""
|
||||
self.assertEqual(self.area.name, "Test Area")
|
||||
self.assertEqual(self.area.slug, "test-area")
|
||||
self.assertEqual(self.area.park, self.park)
|
||||
|
||||
def test_historical_slug_lookup(self):
|
||||
"""Test finding area by historical slug"""
|
||||
# Change area name/slug
|
||||
self.area.name = "Updated Area Name"
|
||||
self.area.save()
|
||||
|
||||
# Try to find by old slug
|
||||
area, is_historical = ParkArea.get_by_slug("test-area")
|
||||
self.assertEqual(area.id, self.area.id)
|
||||
self.assertTrue(is_historical)
|
||||
|
||||
# Try current slug
|
||||
area, is_historical = ParkArea.get_by_slug("updated-area-name")
|
||||
self.assertEqual(area.id, self.area.id)
|
||||
self.assertFalse(is_historical)
|
||||
|
||||
def test_unique_together_constraint(self):
|
||||
"""Test unique_together constraint for park and slug"""
|
||||
# Try to create area with same slug in same park
|
||||
with self.assertRaises(ValidationError):
|
||||
ParkArea.objects.create(
|
||||
park=self.park,
|
||||
name="Test Area" # Will generate same slug
|
||||
)
|
||||
|
||||
# Should be able to use same name in different park
|
||||
other_park = Park.objects.create(name="Other Park")
|
||||
area = ParkArea.objects.create(
|
||||
park=other_park,
|
||||
name="Test Area"
|
||||
)
|
||||
self.assertEqual(area.slug, "test-area")
|
||||
|
||||
def test_absolute_url(self):
|
||||
"""Test get_absolute_url method"""
|
||||
expected_url = f"/parks/{self.park.slug}/areas/{self.area.slug}/"
|
||||
self.assertEqual(self.area.get_absolute_url(), expected_url)
|
||||
Reference in New Issue
Block a user