mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 05:11:10 -05:00
771 lines
29 KiB
Python
771 lines
29 KiB
Python
"""
|
|
Comprehensive tests for Rides API endpoints.
|
|
|
|
This module provides extensive test coverage for:
|
|
- RideListCreateAPIView: List and create ride operations
|
|
- RideDetailAPIView: Retrieve, update, delete operations
|
|
- FilterOptionsAPIView: Filter option retrieval
|
|
- HybridRideAPIView: Intelligent hybrid filtering strategy
|
|
- RideFilterMetadataAPIView: Filter metadata retrieval
|
|
- RideSearchSuggestionsAPIView: Search suggestions
|
|
- CompanySearchAPIView: Company autocomplete search
|
|
- RideModelSearchAPIView: Ride model autocomplete search
|
|
- RideImageSettingsAPIView: Ride image configuration
|
|
|
|
Test patterns follow Django styleguide conventions.
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import patch, MagicMock
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
from rest_framework import status
|
|
from rest_framework.test import APITestCase, APIClient
|
|
|
|
from tests.factories import (
|
|
UserFactory,
|
|
StaffUserFactory,
|
|
SuperUserFactory,
|
|
ParkFactory,
|
|
RideFactory,
|
|
CoasterFactory,
|
|
CompanyFactory,
|
|
ManufacturerCompanyFactory,
|
|
DesignerCompanyFactory,
|
|
RideModelFactory,
|
|
)
|
|
from tests.test_utils import EnhancedAPITestCase
|
|
|
|
|
|
class TestRideListAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideListCreateAPIView GET endpoint."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.park = ParkFactory()
|
|
self.manufacturer = ManufacturerCompanyFactory()
|
|
self.designer = DesignerCompanyFactory()
|
|
self.rides = [
|
|
RideFactory(
|
|
park=self.park,
|
|
manufacturer=self.manufacturer,
|
|
designer=self.designer,
|
|
name='Alpha Coaster',
|
|
status='OPERATING',
|
|
category='RC'
|
|
),
|
|
RideFactory(
|
|
park=self.park,
|
|
manufacturer=self.manufacturer,
|
|
name='Beta Ride',
|
|
status='OPERATING',
|
|
category='DR'
|
|
),
|
|
RideFactory(
|
|
park=self.park,
|
|
name='Gamma Coaster',
|
|
status='CLOSED_TEMP',
|
|
category='RC'
|
|
),
|
|
]
|
|
self.url = '/api/v1/rides/'
|
|
|
|
def test__ride_list__unauthenticated__can_access(self):
|
|
"""Test that unauthenticated users can access ride list."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__returns_paginated_results(self):
|
|
"""Test that ride list returns paginated results."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
# Should have pagination info
|
|
self.assertIn('results', response.data)
|
|
self.assertIn('count', response.data)
|
|
|
|
def test__ride_list__with_search__returns_matching_rides(self):
|
|
"""Test search functionality."""
|
|
response = self.client.get(self.url, {'search': 'Alpha'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
# Should find Alpha Coaster
|
|
results = response.data.get('results', [])
|
|
if results:
|
|
names = [r.get('name', '') for r in results]
|
|
self.assertTrue(any('Alpha' in name for name in names))
|
|
|
|
def test__ride_list__with_park_slug__returns_filtered_rides(self):
|
|
"""Test filtering by park slug."""
|
|
response = self.client.get(self.url, {'park_slug': self.park.slug})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_park_id__returns_filtered_rides(self):
|
|
"""Test filtering by park ID."""
|
|
response = self.client.get(self.url, {'park_id': self.park.id})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_category_filter__returns_filtered_rides(self):
|
|
"""Test filtering by category."""
|
|
response = self.client.get(self.url, {'category': 'RC'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
# All returned rides should be roller coasters
|
|
for ride in response.data.get('results', []):
|
|
self.assertEqual(ride.get('category'), 'RC')
|
|
|
|
def test__ride_list__with_status_filter__returns_filtered_rides(self):
|
|
"""Test filtering by status."""
|
|
response = self.client.get(self.url, {'status': 'OPERATING'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
for ride in response.data.get('results', []):
|
|
self.assertEqual(ride.get('status'), 'OPERATING')
|
|
|
|
def test__ride_list__with_manufacturer_filter__returns_filtered_rides(self):
|
|
"""Test filtering by manufacturer ID."""
|
|
response = self.client.get(self.url, {'manufacturer_id': self.manufacturer.id})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_manufacturer_slug__returns_filtered_rides(self):
|
|
"""Test filtering by manufacturer slug."""
|
|
response = self.client.get(self.url, {'manufacturer_slug': self.manufacturer.slug})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_designer_filter__returns_filtered_rides(self):
|
|
"""Test filtering by designer ID."""
|
|
response = self.client.get(self.url, {'designer_id': self.designer.id})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_rating_filters__returns_filtered_rides(self):
|
|
"""Test filtering by rating range."""
|
|
response = self.client.get(self.url, {'min_rating': 5, 'max_rating': 10})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_height_requirement_filters__returns_filtered_rides(self):
|
|
"""Test filtering by height requirement."""
|
|
response = self.client.get(self.url, {
|
|
'min_height_requirement': 36,
|
|
'max_height_requirement': 54
|
|
})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_capacity_filters__returns_filtered_rides(self):
|
|
"""Test filtering by capacity."""
|
|
response = self.client.get(self.url, {'min_capacity': 500, 'max_capacity': 3000})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_opening_year_filters__returns_filtered_rides(self):
|
|
"""Test filtering by opening year."""
|
|
response = self.client.get(self.url, {
|
|
'min_opening_year': 2000,
|
|
'max_opening_year': 2024
|
|
})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_ordering__returns_ordered_results(self):
|
|
"""Test ordering functionality."""
|
|
response = self.client.get(self.url, {'ordering': '-name'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_multiple_filters__returns_combined_results(self):
|
|
"""Test combining multiple filters."""
|
|
response = self.client.get(self.url, {
|
|
'category': 'RC',
|
|
'status': 'OPERATING',
|
|
'ordering': 'name'
|
|
})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__pagination__page_size_respected(self):
|
|
"""Test that page_size parameter is respected."""
|
|
response = self.client.get(self.url, {'page_size': 1})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
results = response.data.get('results', [])
|
|
self.assertLessEqual(len(results), 1)
|
|
|
|
|
|
class TestRideCreateAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideListCreateAPIView POST endpoint."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.user = UserFactory()
|
|
self.staff_user = StaffUserFactory()
|
|
self.park = ParkFactory()
|
|
self.manufacturer = ManufacturerCompanyFactory()
|
|
self.url = '/api/v1/rides/'
|
|
|
|
self.valid_ride_data = {
|
|
'name': 'New Test Ride',
|
|
'description': 'A test ride for API testing',
|
|
'park_id': self.park.id,
|
|
'category': 'RC',
|
|
'status': 'OPERATING',
|
|
}
|
|
|
|
def test__ride_create__unauthenticated__returns_401(self):
|
|
"""Test that unauthenticated users cannot create rides."""
|
|
response = self.client.post(self.url, self.valid_ride_data)
|
|
|
|
# Based on the view, AllowAny is used, so it might allow creation
|
|
# If not, it should be 401
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_201_CREATED,
|
|
status.HTTP_401_UNAUTHORIZED,
|
|
status.HTTP_400_BAD_REQUEST
|
|
])
|
|
|
|
def test__ride_create__with_valid_data__creates_ride(self):
|
|
"""Test creating ride with valid data."""
|
|
self.client.force_authenticate(user=self.user)
|
|
response = self.client.post(self.url, self.valid_ride_data)
|
|
|
|
# Should create or return validation error if models not available
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_201_CREATED,
|
|
status.HTTP_400_BAD_REQUEST,
|
|
status.HTTP_501_NOT_IMPLEMENTED
|
|
])
|
|
|
|
def test__ride_create__with_invalid_park__returns_error(self):
|
|
"""Test creating ride with invalid park ID."""
|
|
self.client.force_authenticate(user=self.user)
|
|
invalid_data = self.valid_ride_data.copy()
|
|
invalid_data['park_id'] = 99999
|
|
|
|
response = self.client.post(self.url, invalid_data)
|
|
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_400_BAD_REQUEST,
|
|
status.HTTP_404_NOT_FOUND,
|
|
status.HTTP_501_NOT_IMPLEMENTED
|
|
])
|
|
|
|
def test__ride_create__with_manufacturer__creates_ride_with_relationship(self):
|
|
"""Test creating ride with manufacturer relationship."""
|
|
self.client.force_authenticate(user=self.user)
|
|
data_with_manufacturer = self.valid_ride_data.copy()
|
|
data_with_manufacturer['manufacturer_id'] = self.manufacturer.id
|
|
|
|
response = self.client.post(self.url, data_with_manufacturer)
|
|
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_201_CREATED,
|
|
status.HTTP_400_BAD_REQUEST,
|
|
status.HTTP_501_NOT_IMPLEMENTED
|
|
])
|
|
|
|
|
|
class TestRideDetailAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideDetailAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.user = UserFactory()
|
|
self.park = ParkFactory()
|
|
self.ride = RideFactory(park=self.park)
|
|
self.url = f'/api/v1/rides/{self.ride.id}/'
|
|
|
|
def test__ride_detail__unauthenticated__can_access(self):
|
|
"""Test that unauthenticated users can access ride detail."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_detail__returns_full_ride_data(self):
|
|
"""Test that ride detail returns all expected fields."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
expected_fields = ['id', 'name', 'description', 'category', 'status', 'park']
|
|
for field in expected_fields:
|
|
self.assertIn(field, response.data)
|
|
|
|
def test__ride_detail__invalid_id__returns_404(self):
|
|
"""Test that invalid ride ID returns 404."""
|
|
response = self.client.get('/api/v1/rides/99999/')
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
class TestRideUpdateAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideDetailAPIView PATCH/PUT."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.user = UserFactory()
|
|
self.park = ParkFactory()
|
|
self.ride = RideFactory(park=self.park)
|
|
self.url = f'/api/v1/rides/{self.ride.id}/'
|
|
|
|
def test__ride_update__partial_update__updates_field(self):
|
|
"""Test partial update (PATCH)."""
|
|
self.client.force_authenticate(user=self.user)
|
|
|
|
update_data = {'description': 'Updated description'}
|
|
response = self.client.patch(self.url, update_data)
|
|
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_200_OK,
|
|
status.HTTP_401_UNAUTHORIZED,
|
|
status.HTTP_403_FORBIDDEN
|
|
])
|
|
|
|
def test__ride_update__move_to_new_park__updates_relationship(self):
|
|
"""Test moving ride to a different park."""
|
|
self.client.force_authenticate(user=self.user)
|
|
new_park = ParkFactory()
|
|
|
|
update_data = {'park_id': new_park.id}
|
|
response = self.client.patch(self.url, update_data)
|
|
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_200_OK,
|
|
status.HTTP_401_UNAUTHORIZED,
|
|
status.HTTP_403_FORBIDDEN
|
|
])
|
|
|
|
|
|
class TestRideDeleteAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideDetailAPIView DELETE."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.user = UserFactory()
|
|
self.park = ParkFactory()
|
|
self.ride = RideFactory(park=self.park)
|
|
self.url = f'/api/v1/rides/{self.ride.id}/'
|
|
|
|
def test__ride_delete__authenticated__deletes_ride(self):
|
|
"""Test deleting a ride."""
|
|
self.client.force_authenticate(user=self.user)
|
|
response = self.client.delete(self.url)
|
|
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_204_NO_CONTENT,
|
|
status.HTTP_401_UNAUTHORIZED,
|
|
status.HTTP_403_FORBIDDEN
|
|
])
|
|
|
|
|
|
class TestFilterOptionsAPIView(EnhancedAPITestCase):
|
|
"""Test cases for FilterOptionsAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.url = '/api/v1/rides/filter-options/'
|
|
|
|
def test__filter_options__returns_all_options(self):
|
|
"""Test that filter options endpoint returns all filter options."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
# Check for expected filter categories
|
|
expected_keys = ['categories', 'statuses']
|
|
for key in expected_keys:
|
|
self.assertIn(key, response.data)
|
|
|
|
def test__filter_options__includes_ranges(self):
|
|
"""Test that filter options include numeric ranges."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertIn('ranges', response.data)
|
|
|
|
def test__filter_options__includes_ordering_options(self):
|
|
"""Test that filter options include ordering options."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertIn('ordering_options', response.data)
|
|
|
|
|
|
class TestHybridRideAPIView(EnhancedAPITestCase):
|
|
"""Test cases for HybridRideAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.park = ParkFactory()
|
|
self.manufacturer = ManufacturerCompanyFactory()
|
|
self.rides = [
|
|
RideFactory(park=self.park, manufacturer=self.manufacturer, status='OPERATING', category='RC'),
|
|
RideFactory(park=self.park, status='OPERATING', category='DR'),
|
|
RideFactory(park=self.park, status='CLOSED_TEMP', category='RC'),
|
|
]
|
|
self.url = '/api/v1/rides/hybrid/'
|
|
|
|
def test__hybrid_ride__initial_load__returns_rides(self):
|
|
"""Test initial load returns rides with metadata."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertTrue(response.data.get('success', False))
|
|
self.assertIn('data', response.data)
|
|
self.assertIn('rides', response.data['data'])
|
|
self.assertIn('total_count', response.data['data'])
|
|
|
|
def test__hybrid_ride__with_category_filter__returns_filtered_rides(self):
|
|
"""Test filtering by category."""
|
|
response = self.client.get(self.url, {'category': 'RC'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_status_filter__returns_filtered_rides(self):
|
|
"""Test filtering by status."""
|
|
response = self.client.get(self.url, {'status': 'OPERATING'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_park_slug__returns_filtered_rides(self):
|
|
"""Test filtering by park slug."""
|
|
response = self.client.get(self.url, {'park_slug': self.park.slug})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_manufacturer_filter__returns_filtered_rides(self):
|
|
"""Test filtering by manufacturer."""
|
|
response = self.client.get(self.url, {'manufacturer': self.manufacturer.slug})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_offset__returns_progressive_data(self):
|
|
"""Test progressive loading with offset."""
|
|
response = self.client.get(self.url, {'offset': 0})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertIn('has_more', response.data['data'])
|
|
|
|
def test__hybrid_ride__with_invalid_offset__returns_400(self):
|
|
"""Test invalid offset parameter."""
|
|
response = self.client.get(self.url, {'offset': 'invalid'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
def test__hybrid_ride__with_search__returns_matching_rides(self):
|
|
"""Test search functionality."""
|
|
response = self.client.get(self.url, {'search': 'test'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_rating_filters__returns_filtered_rides(self):
|
|
"""Test filtering by rating range."""
|
|
response = self.client.get(self.url, {'rating_min': 5.0, 'rating_max': 10.0})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_height_filters__returns_filtered_rides(self):
|
|
"""Test filtering by height requirement range."""
|
|
response = self.client.get(self.url, {
|
|
'height_requirement_min': 36,
|
|
'height_requirement_max': 54
|
|
})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_roller_coaster_filters__returns_filtered_rides(self):
|
|
"""Test filtering by roller coaster specific fields."""
|
|
response = self.client.get(self.url, {
|
|
'roller_coaster_type': 'SITDOWN',
|
|
'track_material': 'STEEL'
|
|
})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__hybrid_ride__with_inversions_filter__returns_filtered_rides(self):
|
|
"""Test filtering by inversions."""
|
|
response = self.client.get(self.url, {'has_inversions': 'true'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
|
|
class TestRideFilterMetadataAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideFilterMetadataAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.url = '/api/v1/rides/filter-metadata/'
|
|
|
|
def test__filter_metadata__unscoped__returns_all_metadata(self):
|
|
"""Test getting unscoped filter metadata."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertTrue(response.data.get('success', False))
|
|
self.assertIn('data', response.data)
|
|
|
|
def test__filter_metadata__scoped__returns_filtered_metadata(self):
|
|
"""Test getting scoped filter metadata."""
|
|
response = self.client.get(self.url, {'scoped': 'true', 'category': 'RC'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
|
|
class TestCompanySearchAPIView(EnhancedAPITestCase):
|
|
"""Test cases for CompanySearchAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.manufacturer = ManufacturerCompanyFactory(name='Bolliger & Mabillard')
|
|
self.url = '/api/v1/rides/search/companies/'
|
|
|
|
def test__company_search__with_query__returns_matching_companies(self):
|
|
"""Test searching for companies."""
|
|
response = self.client.get(self.url, {'q': 'Bolliger'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertIsInstance(response.data, list)
|
|
|
|
def test__company_search__empty_query__returns_empty_list(self):
|
|
"""Test empty query returns empty list."""
|
|
response = self.client.get(self.url, {'q': ''})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(response.data, [])
|
|
|
|
def test__company_search__no_query__returns_empty_list(self):
|
|
"""Test no query parameter returns empty list."""
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(response.data, [])
|
|
|
|
|
|
class TestRideModelSearchAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideModelSearchAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.ride_model = RideModelFactory(name='Hyper Coaster')
|
|
self.url = '/api/v1/rides/search-ride-models/'
|
|
|
|
def test__ride_model_search__with_query__returns_matching_models(self):
|
|
"""Test searching for ride models."""
|
|
response = self.client.get(self.url, {'q': 'Hyper'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertIsInstance(response.data, list)
|
|
|
|
def test__ride_model_search__empty_query__returns_empty_list(self):
|
|
"""Test empty query returns empty list."""
|
|
response = self.client.get(self.url, {'q': ''})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(response.data, [])
|
|
|
|
|
|
class TestRideSearchSuggestionsAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideSearchSuggestionsAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.park = ParkFactory()
|
|
self.ride = RideFactory(park=self.park, name='Superman: Escape from Krypton')
|
|
self.url = '/api/v1/rides/search-suggestions/'
|
|
|
|
def test__search_suggestions__with_query__returns_suggestions(self):
|
|
"""Test getting search suggestions."""
|
|
response = self.client.get(self.url, {'q': 'Superman'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertIsInstance(response.data, list)
|
|
|
|
def test__search_suggestions__empty_query__returns_empty_list(self):
|
|
"""Test empty query returns empty list."""
|
|
response = self.client.get(self.url, {'q': ''})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(response.data, [])
|
|
|
|
|
|
class TestRideImageSettingsAPIView(EnhancedAPITestCase):
|
|
"""Test cases for RideImageSettingsAPIView."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.user = UserFactory()
|
|
self.park = ParkFactory()
|
|
self.ride = RideFactory(park=self.park)
|
|
self.url = f'/api/v1/rides/{self.ride.id}/image-settings/'
|
|
|
|
def test__image_settings__patch__updates_settings(self):
|
|
"""Test updating ride image settings."""
|
|
self.client.force_authenticate(user=self.user)
|
|
|
|
response = self.client.patch(self.url, {})
|
|
|
|
# Should handle the request
|
|
self.assertIn(response.status_code, [
|
|
status.HTTP_200_OK,
|
|
status.HTTP_400_BAD_REQUEST,
|
|
status.HTTP_401_UNAUTHORIZED
|
|
])
|
|
|
|
def test__image_settings__invalid_ride__returns_404(self):
|
|
"""Test updating image settings for non-existent ride."""
|
|
self.client.force_authenticate(user=self.user)
|
|
|
|
response = self.client.patch('/api/v1/rides/99999/image-settings/', {})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
class TestRideAPIRollerCoasterFilters(EnhancedAPITestCase):
|
|
"""Test cases for roller coaster specific filters."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.park = ParkFactory()
|
|
# Create coasters with different stats
|
|
self.coaster1 = CoasterFactory(park=self.park, name='Steel Vengeance')
|
|
self.coaster2 = CoasterFactory(park=self.park, name='Millennium Force')
|
|
self.url = '/api/v1/rides/'
|
|
|
|
def test__ride_list__with_roller_coaster_type__filters_correctly(self):
|
|
"""Test filtering by roller coaster type."""
|
|
response = self.client.get(self.url, {'roller_coaster_type': 'SITDOWN'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_track_material__filters_correctly(self):
|
|
"""Test filtering by track material."""
|
|
response = self.client.get(self.url, {'track_material': 'STEEL'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_propulsion_system__filters_correctly(self):
|
|
"""Test filtering by propulsion system."""
|
|
response = self.client.get(self.url, {'propulsion_system': 'CHAIN'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_height_ft_range__filters_correctly(self):
|
|
"""Test filtering by height in feet."""
|
|
response = self.client.get(self.url, {'min_height_ft': 100, 'max_height_ft': 500})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_speed_mph_range__filters_correctly(self):
|
|
"""Test filtering by speed in mph."""
|
|
response = self.client.get(self.url, {'min_speed_mph': 50, 'max_speed_mph': 150})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__with_inversions_range__filters_correctly(self):
|
|
"""Test filtering by number of inversions."""
|
|
response = self.client.get(self.url, {'min_inversions': 0, 'max_inversions': 14})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__ordering_by_height__orders_correctly(self):
|
|
"""Test ordering by height."""
|
|
response = self.client.get(self.url, {'ordering': '-height_ft'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__ordering_by_speed__orders_correctly(self):
|
|
"""Test ordering by speed."""
|
|
response = self.client.get(self.url, {'ordering': '-speed_mph'})
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
|
|
class TestRideAPIEdgeCases(EnhancedAPITestCase):
|
|
"""Test cases for edge cases in ride APIs."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
|
|
def test__ride_list__empty_database__returns_empty_list(self):
|
|
"""Test API behavior with no rides in database."""
|
|
# This depends on existing data, just verify no error
|
|
response = self.client.get('/api/v1/rides/')
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__special_characters_in_search__handled_safely(self):
|
|
"""Test that special characters in search are handled safely."""
|
|
special_searches = [
|
|
"O'Brien",
|
|
"Ride & Coaster",
|
|
"Test; DROP TABLE rides;",
|
|
"Ride<script>alert(1)</script>",
|
|
]
|
|
|
|
for search_term in special_searches:
|
|
response = self.client.get('/api/v1/rides/', {'search': search_term})
|
|
# Should not crash
|
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_400_BAD_REQUEST])
|
|
|
|
def test__ride_list__extreme_pagination__handled_safely(self):
|
|
"""Test extreme pagination values."""
|
|
response = self.client.get('/api/v1/rides/', {'page': 99999, 'page_size': 1000})
|
|
|
|
# Should handle gracefully
|
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND])
|
|
|
|
def test__ride_list__invalid_ordering__handled_safely(self):
|
|
"""Test invalid ordering parameter."""
|
|
response = self.client.get('/api/v1/rides/', {'ordering': 'invalid_field'})
|
|
|
|
# Should use default ordering
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
|
|
class TestRideAPIQueryOptimization(EnhancedAPITestCase):
|
|
"""Test cases for query optimization in ride APIs."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
self.client = APIClient()
|
|
self.park = ParkFactory()
|
|
|
|
def test__ride_list__uses_select_related(self):
|
|
"""Test that ride list uses select_related for optimization."""
|
|
# Create multiple rides
|
|
for i in range(5):
|
|
RideFactory(park=self.park)
|
|
|
|
response = self.client.get('/api/v1/rides/')
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
|
|
def test__ride_list__handles_large_dataset(self):
|
|
"""Test that ride list handles larger datasets efficiently."""
|
|
# Create batch of rides
|
|
for i in range(10):
|
|
RideFactory(park=self.park, name=f'Ride {i}')
|
|
|
|
response = self.client.get('/api/v1/rides/')
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|