Coverage for src/api/tests/test_spot_creation.py: 100%
63 statements
« prev ^ index » next coverage.py v7.11.1, created at 2025-11-08 10:41 +0000
« prev ^ index » next coverage.py v7.11.1, created at 2025-11-08 10:41 +0000
1# src/api/tests/test_spot_creation.py
3from django.urls import reverse
4from rest_framework.test import APIClient
5from rest_framework import status
6from django.contrib.auth.models import User
7from src.api.models import ParkingLot, OperatorProfile
8import pytest
11@pytest.mark.django_db
12class TestSpotCreation:
13 """Test suite for spot creation by operators"""
15 def setup_method(self):
16 """Set up test data before each test"""
17 # Create parking lots
18 self.lot = ParkingLot.objects.create(
19 name="Central",
20 city="Kyiv",
21 street="Main"
22 )
23 self.other_lot = ParkingLot.objects.create(
24 name="West",
25 city="Lviv",
26 street="Green"
27 )
29 # Create users (no password needed with force_authenticate)
30 self.operator = User.objects.create_user(username="op1")
31 self.not_operator = User.objects.create_user(username="u1")
33 # Assign operator to lot
34 OperatorProfile.objects.create(user=self.operator, lot=self.lot)
36 # Create client
37 self.client = APIClient()
39 def test_operator_creates_spot_in_own_lot_201(self):
40 """Operator can successfully create a spot in their assigned lot"""
41 # Use force_authenticate instead of login
42 self.client.force_authenticate(user=self.operator)
44 url = f"/api/v1/lots/{self.lot.id}/spots/create/"
45 payload = {"number": "A1", "is_ev": True, "is_disabled": False}
47 resp = self.client.post(url, payload, format="json")
49 assert resp.status_code == status.HTTP_201_CREATED
50 assert resp.data["number"] == "A1"
51 assert resp.data["lot"] == self.lot.id
53 def test_operator_cannot_create_duplicate_spot_number_400(self):
54 """Operator cannot create spots with duplicate numbers in same lot"""
55 self.client.force_authenticate(user=self.operator)
57 url = f"/api/v1/lots/{self.lot.id}/spots/create/"
58 payload = {"number": "A1", "is_ev": True, "is_disabled": False}
60 # Create first spot
61 resp1 = self.client.post(url, payload, format="json")
62 assert resp1.status_code == status.HTTP_201_CREATED
64 # Try to create duplicate
65 resp2 = self.client.post(url, payload, format="json")
66 assert resp2.status_code == status.HTTP_400_BAD_REQUEST
67 assert "number" in resp2.data
69 def test_operator_cannot_create_spot_in_other_lot(self):
70 """Operator cannot create spots in lots they don't manage"""
71 self.client.force_authenticate(user=self.operator)
73 url = f"/api/v1/lots/{self.other_lot.id}/spots/create/"
74 payload = {"number": "X1", "is_ev": False, "is_disabled": False}
76 resp = self.client.post(url, payload, format="json")
78 assert resp.status_code == status.HTTP_403_FORBIDDEN
79 assert "detail" in resp.data
81 def test_non_operator_cannot_create_spot(self):
82 """Regular users without operator profile cannot create spots"""
83 self.client.force_authenticate(user=self.not_operator)
85 url = f"/api/v1/lots/{self.lot.id}/spots/create/"
86 payload = {"number": "B1", "is_ev": False, "is_disabled": False}
88 resp = self.client.post(url, payload, format="json")
90 assert resp.status_code == status.HTTP_403_FORBIDDEN
91 assert "detail" in resp.data
93 def test_operator_cannot_create_spot_with_empty_number(self):
94 """Operator cannot create spot with empty spot number"""
95 self.client.force_authenticate(user=self.operator)
97 url = f"/api/v1/lots/{self.lot.id}/spots/create/"
98 payload = {"number": "", "is_ev": False, "is_disabled": False}
100 resp = self.client.post(url, payload, format="json")
102 assert resp.status_code == status.HTTP_400_BAD_REQUEST
103 assert "number" in resp.data
105 def test_operator_cannot_create_spot_with_same_number_different_case(self):
106 """Spot numbers are case-insensitive (A1 == a1)"""
107 self.client.force_authenticate(user=self.operator)
109 url = f"/api/v1/lots/{self.lot.id}/spots/create/"
111 # Create first spot
112 payload1 = {"number": "A1", "is_ev": False, "is_disabled": False}
113 resp1 = self.client.post(url, payload1, format="json")
114 assert resp1.status_code == status.HTTP_201_CREATED
116 # Try to create same number with different case
117 payload2 = {"number": "a1", "is_ev": False, "is_disabled": False}
118 resp2 = self.client.post(url, payload2, format="json")
120 assert resp2.status_code == status.HTTP_400_BAD_REQUEST
121 assert "number" in resp2.data