+
1 import json
+
+
2 from datetime import datetime
+
+
3 from unittest.mock import mock_open, patch
+
+
4 from utils import (
+
+
5 load_clubs,
+
+
6 load_competitions,
+
+
7 get_club_by_email,
+
+
8 lower_case_email,
+
+
9 strip_white_space,
+
+
10 get_competition_by_name,
+
+
11 get_club_by_name,
+
+
12 get_club_points,
+
+
13 get_competition_places,
+
+
14 is_competition_bookable,
+
+
15 is_booking_valid,
+
+
16 update_club_points,
+
+
17 update_competition_places,
+
+
18 get_booking_key,
+
+
19 get_logged_club,
+
+
20 )
+
+
21
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
22 class TestLoadClubs:
+
+
23 def test_returns_all_clubs(self, mock_clubs):
+
+
24 """Case 1 โ valid file with multiple clubs: returns all elements."""
+
+
25 data = json.dumps({"clubs": mock_clubs})
+
+
26 with patch("builtins.open", mock_open(read_data=data)):
+
+
27 result = load_clubs()
+
+
28 assert len(result) == 3
+
+
29
+
+
30 def test_each_club_has_required_keys(self, mock_clubs):
+
+
31 """Case 2 โ each club contains the name, email, and points keys."""
+
+
32 data = json.dumps({"clubs": mock_clubs})
+
+
33 with patch("builtins.open", mock_open(read_data=data)):
+
+
34 result = load_clubs()
+
+
35 for club in result:
+
+
36 assert "name" in club
+
+
37 assert "email" in club
+
+
38 assert "points" in club
+
+
39
+
+
40 def test_returns_single_club(self):
+
+
+
+
+ -
+
+ E501
+
+ Line too long (84 > 79 characters)
+
+
41 """Case 3 โ valid file with a single club: returns list with one element."""
+
+
42 club = [{"name": "Simply Lift",
+
+
43 "email": "john@simplylift.co", "points": "13"}]
+
+
44 data = json.dumps({"clubs": club})
+
+
45 with patch("builtins.open", mock_open(read_data=data)):
+
+
46 result = load_clubs()
+
+
47 assert len(result) == 1
+
+
48 assert result[0]["name"] == "Simply Lift"
+
+
49
+
+
50 def test_returns_empty_list_when_clubs_is_empty(self):
+
+
51 """Case 4 โ 'clubs' key present but empty list: returns []. """
+
+
52 data = json.dumps({"clubs": []})
+
+
53 with patch("builtins.open", mock_open(read_data=data)):
+
+
54 result = load_clubs()
+
+
55 assert result == []
+
+
56
+
+
57 def test_raises_file_not_found_when_file_missing(self):
+
+
58 """Case 5 โ file not found: returns None."""
+
+
59 with patch("builtins.open", side_effect=FileNotFoundError):
+
+
60 assert load_clubs() is None
+
+
61
+
+
62 def test_raises_json_decode_error_on_invalid_json(self):
+
+
63 """Case 6 โ invalid JSON content: returns None."""
+
+
64 with patch("builtins.open", mock_open(read_data="not valid json {")):
+
+
65 assert load_clubs() is None
+
+
66
+
+
67 def test_raises_key_error_when_clubs_key_missing(self):
+
+
68 """Case 7 โ 'clubs' key missing from JSON: returns None."""
+
+
69 data = json.dumps({"wrong_key": []})
+
+
70 with patch("builtins.open", mock_open(read_data=data)):
+
+
71 assert load_clubs() is None
+
+
72
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
73 class TestLoadCompetitions:
+
+
74 def test_returns_all_competitions(self, mock_competitions):
+
+
75 """Case 1 โ valid file with multiple competitions: all elements."""
+
+
76 data = json.dumps({"competitions": mock_competitions})
+
+
77 with patch("builtins.open", mock_open(read_data=data)):
+
+
78 result = load_competitions()
+
+
79 assert len(result) == 2
+
+
80
+
+
81 def test_each_competition_has_required_keys(self, mock_competitions):
+
+
82 """Case 2 โ each competition has name, date, number_of_places keys."""
+
+
83 data = json.dumps({"competitions": mock_competitions})
+
+
84 with patch("builtins.open", mock_open(read_data=data)):
+
+
85 result = load_competitions()
+
+
86 for competition in result:
+
+
87 assert "name" in competition
+
+
88 assert "date" in competition
+
+
89 assert "number_of_places" in competition
+
+
90
+
+
91 def test_returns_single_competition(self):
+
+
+
+
+ -
+
+ E501
+
+ Line too long (81 > 79 characters)
+
+
92 """Case 3 โ valid file with single competition: list with one element."""
+
+
93 competition = [{
+
+
94 "name": "Spring Festival",
+
+
95 "date": "2025-03-27 10:00:00",
+
+
96 "number_of_places": "25"
+
+
97 }]
+
+
98 data = json.dumps({"competitions": competition})
+
+
99 with patch("builtins.open", mock_open(read_data=data)):
+
+
100 result = load_competitions()
+
+
101 assert len(result) == 1
+
+
102 assert result[0]["name"] == "Spring Festival"
+
+
103
+
+
104 def test_returns_empty_list_when_competitions_is_empty(self):
+
+
105 """Case 4 โ 'competitions' key present but empty list: []. """
+
+
106 data = json.dumps({"competitions": []})
+
+
107 with patch("builtins.open", mock_open(read_data=data)):
+
+
108 result = load_competitions()
+
+
109 assert result == []
+
+
110
+
+
111 def test_raises_file_not_found_when_file_missing(self):
+
+
112 """Case 5 โ file not found: returns None."""
+
+
113 with patch("builtins.open", side_effect=FileNotFoundError):
+
+
114 assert load_competitions() is None
+
+
115
+
+
116 def test_raises_json_decode_error_on_invalid_json(self):
+
+
117 """Case 6 โ invalid JSON content: returns None."""
+
+
118 with patch("builtins.open", mock_open(read_data="not valid json {")):
+
+
119 assert load_competitions() is None
+
+
120
+
+
121 def test_raises_key_error_when_competitions_key_missing(self):
+
+
122 """Case 7 โ 'competitions' key missing from JSON: returns None."""
+
+
123 data = json.dumps({"wrong_key": []})
+
+
124 with patch("builtins.open", mock_open(read_data=data)):
+
+
125 assert load_competitions() is None
+
+
126
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
127 class TestGetClubByEmail:
+
+
128 def test_get_club_with_valid_email(self, mock_clubs):
+
+
129 """Case 1 โ valid email: returns the corresponding club."""
+
+
130 valid_email = "john@simplylift.co"
+
+
131 expected_club = {
+
+
132 "name": "Simply Lift",
+
+
133 "email": "john@simplylift.co",
+
+
134 "points": "13"
+
+
135 }
+
+
136 assert get_club_by_email(valid_email, mock_clubs) == expected_club
+
+
137
+
+
138 def test_get_club_with_invalid_email(self, mock_clubs):
+
+
139 """Case 2 โ invalid email: returns None."""
+
+
140 invalid_email = "invalid@simplylift.co"
+
+
141 assert get_club_by_email(invalid_email, mock_clubs) is None
+
+
142
+
+
143 def test_get_club_with_empty_clubs_list(self):
+
+
144 """Case 3 โ empty clubs list: returns None."""
+
+
145 empty_clubs = []
+
+
146 email = "john@example.com"
+
+
147 assert get_club_by_email(email, empty_clubs) is None
+
+
148
+
+
149 def test_get_club_with_multiple_clubs_same_email(self):
+
+
150 """Case 4 โ multiple clubs same email: returns first club found."""
+
+
151 clubs_with_duplicate_email = [
+
+
152 {"name": "Club A", "email": "duplicate@simplylift.co",
+
+
153 "points": "10"},
+
+
154 {"name": "Club B", "email": "duplicate@simplylift.co",
+
+
155 "points": "20"}
+
+
156 ]
+
+
157 email = "duplicate@simplylift.co"
+
+
158 result = get_club_by_email(email, clubs_with_duplicate_email)
+
+
159 assert result == clubs_with_duplicate_email[0]
+
+
160
+
+
161 def test_get_club_with_email_case_sensitivity(self, mock_clubs):
+
+
162 """Case 5 โ email with different case: returns corresponding club."""
+
+
163 email = "John@SimplyLift.co"
+
+
164 expected = {
+
+
165 "name": "Simply Lift",
+
+
166 "email": "john@simplylift.co",
+
+
167 "points": "13"
+
+
168 }
+
+
169 assert get_club_by_email(email, mock_clubs) == expected
+
+
170
+
+
171 def test_get_club_with_email_with_white_space(self, mock_clubs):
+
+
172 """Case 6 โ email with spaces: returns corresponding club."""
+
+
173 email = " john@simplylift.co "
+
+
174 expected = {
+
+
175 "name": "Simply Lift",
+
+
176 "email": "john@simplylift.co",
+
+
177 "points": "13"
+
+
178 }
+
+
179 assert get_club_by_email(email, mock_clubs) == expected
+
+
180
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
181 class TestLowerCaseEmail:
+
+
182 def test_lower_case_email(self):
+
+
183 """Case 1 โ email with uppercase: returns email in lower_case."""
+
+
184 assert lower_case_email("John@SimplyLift.co") == "john@simplylift.co"
+
+
185
+
+
186 def test_lower_case_email_already_lower_case(self):
+
+
187 """Case 2 โ email already lower_case: returns same email."""
+
+
188 assert lower_case_email("john@simplylift.co") == "john@simplylift.co"
+
+
189
+
+
190 def test_lower_case_email_with_white_space(self):
+
+
191 """Case 3 โ email with spaces: lower_case with spaces."""
+
+
192 assert (
+
+
193 lower_case_email(" John@SimplyLift.co ")
+
+
194 == " john@simplylift.co "
+
+
195 )
+
+
196
+
+
197 def test_lower_case_email_empty_string(self):
+
+
198 """Case 4 โ empty email: returns an empty string."""
+
+
199 assert lower_case_email("") == ""
+
+
200
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
201 class TestStripWhiteSpace:
+
+
202 def test_strip_white_space(self):
+
+
203 """Case 1 โ email with spaces before/after: without spaces."""
+
+
+
+
+ -
+
+ E501
+
+ Line too long (82 > 79 characters)
+
+
204 assert strip_white_space(" john@simplylift.co ") == "john@simplylift.co"
+
+
205
+
+
206 def test_strip_white_space_no_spaces(self):
+
+
207 """Case 2 โ email without spaces: returns same email."""
+
+
208 assert strip_white_space("john@simplylift.co") == "john@simplylift.co"
+
+
209
+
+
210 def test_strip_white_space_only_spaces(self):
+
+
211 """Case 3 โ email with only spaces: returns empty string."""
+
+
212 assert strip_white_space(" ") == ""
+
+
213
+
+
214 def test_strip_white_space_empty_string(self):
+
+
215 """Case 4 โ empty email: returns an empty string."""
+
+
216 assert strip_white_space("") == ""
+
+
217
+
+
218 def test_strip_white_space_with_tabs_and_newlines(self):
+
+
219 """Case 5 โ email with tabs/newlines: without tabs/newlines."""
+
+
220 assert strip_white_space("\n\t john@simplylift.co \n\t") == (
+
+
221 "john@simplylift.co"
+
+
222 )
+
+
223
+
+
224 def test_strip_white_space_with_internal_spaces(self):
+
+
225 """Case 6 โ email with internal spaces: only trims edges."""
+
+
226 assert (
+
+
227 strip_white_space(" john @ simplylift . co ")
+
+
228 == "john @ simplylift . co"
+
+
229 )
+
+
230
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
231 class TestGetClubByName:
+
+
232 def test_get_club_with_valid_name(self, mock_clubs):
+
+
233 """Case 1 โ valid club name: returns the corresponding club."""
+
+
234 expected = {
+
+
235 "name": "Simply Lift",
+
+
236 "email": "john@simplylift.co",
+
+
237 "points": "13"
+
+
238 }
+
+
239 assert get_club_by_name("Simply Lift", mock_clubs) == expected
+
+
240
+
+
241 def test_get_club_with_invalid_name(self, mock_clubs):
+
+
242 """Case 2 โ invalid club name: returns None."""
+
+
243 assert get_club_by_name("Nonexistent Club", mock_clubs) is None
+
+
244
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
245 class TestGetCompetitionByName:
+
+
246 def test_get_competition_with_valid_name(self, mock_competitions):
+
+
247 """Case 1 โ valid competition name: returns the competition."""
+
+
248 expected = {
+
+
249 "name": "Spring Festival",
+
+
250 "date": "2025-03-27 10:00:00",
+
+
251 "number_of_places": "25"
+
+
252 }
+
+
253 assert (
+
+
254 get_competition_by_name("Spring Festival", mock_competitions)
+
+
255 == expected
+
+
256 )
+
+
257
+
+
258 def test_get_competition_with_invalid_name(self, mock_competitions):
+
+
259 """Case 2 โ invalid competition name: returns None."""
+
+
260 assert (
+
+
+
+
+ -
+
+ E501
+
+ Line too long (81 > 79 characters)
+
+
261 get_competition_by_name("Nonexistent Competition", mock_competitions)
+
+
262 is None
+
+
263 )
+
+
264
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
265 class TestGetClubPoints:
+
+
266 def test_get_club_points_with_valid_club(self, mock_clubs):
+
+
267 """Case 1 โ valid club: returns the number of points."""
+
+
268 club = {
+
+
269 "name": "Simply Lift",
+
+
270 "email": "john@simplylift.co",
+
+
271 "points": "13"
+
+
272 }
+
+
273 assert get_club_points(club) == 13
+
+
274
+
+
275 def test_get_club_points_with_invalid_club(self, mock_clubs):
+
+
276 """Case 2 โ invalid club: returns None."""
+
+
277 club = {"name": "Invalid Club", "email": "invalid@club.co"}
+
+
278 assert get_club_points(club) is None
+
+
279
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
280 class TestGetCompetitionPlaces:
+
+
+
+
+ -
+
+ E501
+
+ Line too long (84 > 79 characters)
+
+
281 def test_get_competition_places_with_valid_competition(self, mock_competitions):
+
+
282 """Case 1 โ valid competition: returns available places."""
+
+
283 competition = {
+
+
284 "name": "Spring Festival",
+
+
285 "date": "2025-03-27 10:00:00",
+
+
286 "number_of_places": "25"
+
+
287 }
+
+
288 assert get_competition_places(competition) == 25
+
+
289
+
+
290 def test_get_competition_places_with_invalid_competition(self,
+
+
+
+
+ -
+
+ E128
+
+ Continuation line under-indented for visual indent
+
+
291 mock_competitions):
+
+
292 """Case 2 โ invalid competition: returns None."""
+
+
293 competition = {"name": "Invalid", "date": "2025-01-01 00:00:00"}
+
+
294 assert get_competition_places(competition) is None
+
+
295
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
296 class TestIsCompetitionBookable:
+
+
297 def test_returns_true_for_future_competition_with_places(self):
+
+
298 """Case 1 โ future date and places > 0: returns True."""
+
+
299 now = datetime(2026, 6, 22, 12, 0, 0)
+
+
300 competition = {
+
+
301 "name": "Future Open",
+
+
302 "date": "2026-06-23 10:00:00",
+
+
303 "number_of_places": "5",
+
+
304 }
+
+
305 assert is_competition_bookable(competition, now=now) is True
+
+
306
+
+
307 def test_returns_false_for_past_competition(self):
+
+
308 """Case 2 โ past date: returns False."""
+
+
309 now = datetime(2026, 6, 22, 12, 0, 0)
+
+
310 competition = {
+
+
311 "name": "Past Open",
+
+
312 "date": "2026-06-21 10:00:00",
+
+
313 "number_of_places": "5",
+
+
314 }
+
+
315 assert is_competition_bookable(competition, now=now) is False
+
+
316
+
+
317 def test_returns_false_when_no_places_available(self):
+
+
318 """Case 3 โ no places available: returns False."""
+
+
319 now = datetime(2026, 6, 22, 12, 0, 0)
+
+
320 competition = {
+
+
321 "name": "No Places",
+
+
322 "date": "2026-06-23 10:00:00",
+
+
323 "number_of_places": "0",
+
+
324 }
+
+
325 assert is_competition_bookable(competition, now=now) is False
+
+
326
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
327 class TestIsBookingValid:
+
+
328 def test_validate_booking_with_valid_points_and_places(self):
+
+
329 """Case 1 โ enough points and places: returns empty list."""
+
+
330 assert is_booking_valid(10, 5, 3) == []
+
+
331
+
+
332 def test_validate_booking_with_insufficient_club_points(self):
+
+
333 """Case 2 โ insufficient club points: returns error message."""
+
+
334 result = is_booking_valid(2, 5, 3)
+
+
335 expected = [
+
+
336 "Not enough points available in your club to book "
+
+
337 "the requested number of places."
+
+
338 ]
+
+
339 assert result == expected
+
+
340
+
+
341 def test_validate_booking_with_insufficient_competition_places(self):
+
+
342 """Case 3 โ insufficient competition places: returns error message."""
+
+
343 result = is_booking_valid(10, 2, 3)
+
+
344 expected = ["Not enough places available in this competition."]
+
+
345 assert result == expected
+
+
346
+
+
347 def test_validate_booking_with_insufficient_club_points_and_places(self):
+
+
348 """Case 4 โ insufficient points and places: returns both errors."""
+
+
349 result = is_booking_valid(2, 2, 3)
+
+
350 expected = [
+
+
351 "Not enough places available in this competition.",
+
+
352 "Not enough points available in your club to book "
+
+
353 "the requested number of places.",
+
+
354 ]
+
+
355 assert result == expected
+
+
356
+
+
357 def test_validate_booking_with_zero_places_requested(self):
+
+
358 """Case 5 โ request to book zero places: returns error message."""
+
+
359 result = is_booking_valid(10, 5, 0)
+
+
360 expected = ["You need to book at least one place."]
+
+
361 assert result == expected
+
+
362
+
+
363 def test_validate_booking_with_negative_places_requested(self):
+
+
364 """Case 6 โ request negative places: returns error message."""
+
+
365 result = is_booking_valid(10, 5, -1)
+
+
366 expected = ["You cannot book a negative number of places."]
+
+
367 assert result == expected
+
+
368
+
+
369 def test_validate_booking_with_places_exceeding_max_value(self):
+
+
370 """Case 7 โ request more than 12 places: returns error message."""
+
+
371 result = is_booking_valid(15, 25, 13)
+
+
372 expected = ["You cannot book more than 12 places per competition."]
+
+
373 assert result == expected
+
+
374
+
+
375 def test_validate_booking_with_cumulative_places_exceeding_twelve(self):
+
+
376 """Case 8 โ cumulative > 12: returns error."""
+
+
377 result = is_booking_valid(20, 20, 3, places_already_booked=10)
+
+
378 expected = ["You cannot book more than 12 places per competition."]
+
+
379 assert result == expected
+
+
380
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
381 class TestUpdateClubPoints:
+
+
382 def test_update_club_points_with_valid_deduction(self):
+
+
383 """Case 1 โ valid deduction: updates club points."""
+
+
384 club = {"name": "Simply Lift",
+
+
385 "email": "john@simplylift.com", "points": "15"}
+
+
386 assert update_club_points(club, 5) is True
+
+
387 assert club["points"] == "10"
+
+
388
+
+
389 def test_update_club_points_with_deduction_exceeding_current_points(self):
+
+
390 """Case 2 โ deduction exceeds current: no update, returns False."""
+
+
391 club = {"name": "Simply Lift",
+
+
392 "email": "john@simplylift.com", "points": "5"}
+
+
393 assert update_club_points(club, 10) is False
+
+
394 assert club["points"] == "5"
+
+
395
+
+
396 def test_update_club_points_with_invalid_club(self):
+
+
397 """Case 3 โ invalid club: no update, returns False."""
+
+
398 assert update_club_points("Not a dict", 5) is False
+
+
399
+
+
400 def test_update_club_points_with_non_integer_points(self):
+
+
401 """Case 4 โ non-integer points: no update, returns False."""
+
+
402 club = {"name": "Simply Lift",
+
+
403 "email": "john@simplylift.com", "points": "not a number"}
+
+
404 assert update_club_points(club, 5) is False
+
+
405 assert club["points"] == "not a number"
+
+
406
+
+
407 def test_update_club_points_with_negative_deduction(self):
+
+
408 """Case 5 โ negative deduction: no update, returns False."""
+
+
409 club = {"name": "Simply Lift",
+
+
410 "email": "john@simplylift.com", "points": "15"}
+
+
411 assert update_club_points(club, -5) is False
+
+
412 assert club["points"] == "15"
+
+
413
+
+
414 def test_update_club_points_with_zero_deduction(self):
+
+
415 """Case 6 โ zero deduction: no change, returns True."""
+
+
416 club = {"name": "Simply Lift",
+
+
417 "email": "john@simplylift.com", "points": "15"}
+
+
418 assert update_club_points(club, 0) is True
+
+
419 assert club["points"] == "15"
+
+
420
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
421 class TestUpdateCompetitionPlaces:
+
+
422 def test_update_competition_places_with_valid_deduction(self):
+
+
423 """Case 1 โ valid deduction: updates competition places."""
+
+
424 competition = {
+
+
425 "name": "Fall Classic",
+
+
426 "date": "2026-10-22 13:30:00",
+
+
427 "number_of_places": "13"
+
+
428 }
+
+
429 assert update_competition_places(competition, 5) is True
+
+
430 assert competition["number_of_places"] == "8"
+
+
431
+
+
432 def test_update_competition_places_with_deduction_exceeding_places(self):
+
+
433 """Case 2 โ deduction exceeds places: no update, returns False."""
+
+
434 competition = {
+
+
435 "name": "Spring Festival",
+
+
436 "date": "2025-03-27 10:00:00",
+
+
437 "number_of_places": "5"
+
+
438 }
+
+
439 assert update_competition_places(competition, 10) is False
+
+
440 assert competition["number_of_places"] == "5"
+
+
441
+
+
442 def test_update_competition_places_with_invalid_competition(self):
+
+
443 """Case 3 โ invalid competition: no update, returns False."""
+
+
444 assert update_competition_places("Not a dict", 5) is False
+
+
445
+
+
446 def test_update_competition_places_with_non_integer_places(self):
+
+
447 """Case 4 โ non-integer places: no update, returns False."""
+
+
448 competition = {
+
+
449 "name": "Fall Classic",
+
+
450 "date": "2026-10-22 13:30:00",
+
+
451 "number_of_places": "not a number"
+
+
452 }
+
+
453 assert update_competition_places(competition, 5) is False
+
+
454 assert competition["number_of_places"] == "not a number"
+
+
455
+
+
456 def test_update_competition_places_with_negative_deduction(self):
+
+
457 """Case 5 โ negative deduction: no update, returns False."""
+
+
458 competition = {
+
+
459 "name": "Fall Classic",
+
+
460 "date": "2026-10-22 13:30:00",
+
+
461 "number_of_places": "13"
+
+
462 }
+
+
463 assert update_competition_places(competition, -5) is False
+
+
464 assert competition["number_of_places"] == "13"
+
+
465
+
+
466 def test_update_competition_places_with_zero_deduction(self):
+
+
467 """Case 6 โ zero deduction: no change, returns True."""
+
+
468 competition = {
+
+
469 "name": "Fall Classic",
+
+
470 "date": "2026-10-22 13:30:00",
+
+
471 "number_of_places": "13"
+
+
472 }
+
+
473 assert update_competition_places(competition, 0) is True
+
+
474 assert competition["number_of_places"] == "13"
+
+
475
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
476 class TestGetBookingKey:
+
+
477 def test_get_booking_key_with_valid_club_and_competition(self,
+
+
478 mock_clubs,
+
+
+
+
+ -
+
+ E501
+
+ Line too long (80 > 79 characters)
+
+
479 mock_competitions):
+
+
480 """Case 1 โ valid club and competition: returns booking key."""
+
+
481 club = mock_clubs[0]
+
+
482 competition = mock_competitions[0]
+
+
483 expected = f"{club['name']}::{competition['name']}"
+
+
484 assert get_booking_key(club['name'], competition['name']) == expected
+
+
485
+
+
+
+
+ -
+
+ E302
+
+ Expected 2 blank lines, found 1
+
+
486 class TestGetLoggedClub:
+
+
+
+
+ -
+
+ E501
+
+ Line too long (83 > 79 characters)
+
+
487 def test_get_logged_club_with_valid_session(self, request_session, mock_clubs):
+
+
488 """Case 1 โ valid session: returns corresponding club."""
+
+
489 with request_session(mock_clubs[0]['email']):
+
+
490 assert get_logged_club() == mock_clubs[0]
+
+
491
+
+
492 def test_get_logged_club_with_no_session(self, request_session):
+
+
493 """Case 2 โ no session: returns None."""
+
+
494 with request_session():
+
+
495 assert get_logged_club() is None
+
+
496
+
+
497 def test_get_logged_club_with_invalid_session_data(self, request_session):
+
+
498 """Case 3 โ invalid session: returns None."""
+
+
499 with request_session("invalid_email@example.com"):
+
+
+
+
+ -
+
+ W292
+
+ No newline at end of file
+
+
500 assert get_logged_club() is None
+
+
+