1010- URL routing and router registration
1111"""
1212
13+ from types import SimpleNamespace
14+
1315import pytest
1416from django .test import TestCase
1517from django .urls import resolve , reverse
@@ -76,7 +78,10 @@ def test_id_is_read_only(self) -> None:
7678 assert FilterSetSerializer ().fields ["id" ].read_only is True
7779
7880 def test_valid_payload_is_accepted (self ) -> None :
79- serializer = FilterSetSerializer (data = {"name" : "Work Filters" , "filters" : _FILTERS_A , "is_default" : False })
81+ serializer = FilterSetSerializer (
82+ data = {"name" : "Work Filters" , "filters" : _FILTERS_A , "is_default" : False },
83+ context = {"request" : SimpleNamespace (user = self .user )},
84+ )
8085 assert serializer .is_valid (), serializer .errors
8186
8287 def test_name_is_required (self ) -> None :
@@ -90,7 +95,10 @@ def test_filters_is_required(self) -> None:
9095 assert "filters" in serializer .errors
9196
9297 def test_is_default_defaults_to_false_when_omitted (self ) -> None :
93- serializer = FilterSetSerializer (data = {"name" : "Work Filters" , "filters" : _FILTERS_A })
98+ serializer = FilterSetSerializer (
99+ data = {"name" : "Work Filters" , "filters" : _FILTERS_A },
100+ context = {"request" : SimpleNamespace (user = self .user )},
101+ )
94102 assert serializer .is_valid (), serializer .errors
95103 # When omitted, is_default is absent from validated_data (DRF applies the
96104 # default=False at save time, not in validated_data). Either absent or False is correct.
@@ -105,7 +113,37 @@ def test_maps_values_correctly(self) -> None:
105113
106114 def test_filters_accepts_arbitrary_json (self ) -> None :
107115 complex_filters = {"organization_id" : [1 , 2 , 3 ], "date_range" : "custom" , "labels" : [10 , 20 ]}
108- serializer = FilterSetSerializer (data = {"name" : "Complex" , "filters" : complex_filters , "is_default" : False })
116+ serializer = FilterSetSerializer (
117+ data = {"name" : "Complex" , "filters" : complex_filters , "is_default" : False },
118+ context = {"request" : SimpleNamespace (user = self .user )},
119+ )
120+ assert serializer .is_valid (), serializer .errors
121+
122+ def test_validate_rejects_duplicate_name_for_same_user (self ) -> None :
123+ _create_filter_set (self .user , name = "Existing" )
124+ serializer = FilterSetSerializer (
125+ data = {"name" : "Existing" , "filters" : _FILTERS_A , "is_default" : False },
126+ context = {"request" : SimpleNamespace (user = self .user )},
127+ )
128+ assert not serializer .is_valid ()
129+ assert "name" in serializer .errors
130+
131+ def test_validate_allows_same_name_for_different_user (self ) -> None :
132+ other_user = _create_user ("other" )
133+ _create_filter_set (other_user , name = "Shared Name" )
134+ serializer = FilterSetSerializer (
135+ data = {"name" : "Shared Name" , "filters" : _FILTERS_A , "is_default" : False },
136+ context = {"request" : SimpleNamespace (user = self .user )},
137+ )
138+ assert serializer .is_valid (), serializer .errors
139+
140+ def test_validate_allows_updating_instance_without_changing_name (self ) -> None :
141+ instance = _create_filter_set (self .user , name = "Unchanged" )
142+ serializer = FilterSetSerializer (
143+ instance ,
144+ data = {"name" : "Unchanged" , "filters" : _FILTERS_B , "is_default" : False },
145+ context = {"request" : SimpleNamespace (user = self .user )},
146+ )
109147 assert serializer .is_valid (), serializer .errors
110148
111149
@@ -354,6 +392,22 @@ def test_create_without_filters_returns_400(self) -> None:
354392 response = self .client .post (url , {"name" : "No Filters" , "is_default" : False }, format = "json" )
355393 assert response .status_code == status .HTTP_400_BAD_REQUEST
356394
395+ def test_create_with_duplicate_name_for_same_user_returns_400 (self ) -> None :
396+ _create_filter_set (self .user , name = "Duplicate" )
397+ url = reverse ("v1:filter_sets-list" )
398+ response = self .client .post (url , {"name" : "Duplicate" , "filters" : _FILTERS_A , "is_default" : False }, format = "json" )
399+ assert response .status_code == status .HTTP_400_BAD_REQUEST
400+ assert "name" in response .data
401+
402+ def test_create_with_duplicate_name_for_different_user_returns_201 (self ) -> None :
403+ other_user = _create_user ("other" )
404+ _create_filter_set (other_user , name = "Shared Name" )
405+ url = reverse ("v1:filter_sets-list" )
406+ response = self .client .post (
407+ url , {"name" : "Shared Name" , "filters" : _FILTERS_A , "is_default" : False }, format = "json"
408+ )
409+ assert response .status_code == status .HTTP_201_CREATED
410+
357411
358412# =============================================================================
359413# PUT /filter-sets/{id} — full update
@@ -423,6 +477,22 @@ def test_update_does_not_change_owner(self) -> None:
423477 self .filter_set .refresh_from_db ()
424478 assert self .filter_set .user == self .user
425479
480+ def test_update_rejects_rename_to_existing_name (self ) -> None :
481+ """PUT that renames to a name already used by another of the user's filter sets must fail."""
482+ _create_filter_set (self .user , name = "Taken" )
483+ url = reverse ("v1:filter_sets-detail" , kwargs = {"pk" : self .filter_set .pk })
484+ response = self .client .put (url , {"name" : "Taken" , "filters" : _FILTERS_A , "is_default" : False }, format = "json" )
485+ assert response .status_code == status .HTTP_400_BAD_REQUEST
486+ assert "name" in response .data
487+
488+ def test_update_allows_keeping_its_own_name (self ) -> None :
489+ """PUT that keeps the same name on the same instance must not be treated as a duplicate."""
490+ url = reverse ("v1:filter_sets-detail" , kwargs = {"pk" : self .filter_set .pk })
491+ response = self .client .put (
492+ url , {"name" : "Original" , "filters" : _FILTERS_B , "is_default" : False }, format = "json"
493+ )
494+ assert response .status_code == status .HTTP_200_OK
495+
426496
427497# =============================================================================
428498# DELETE /filter-sets/{id} — destroy
0 commit comments