Skip to content

Commit 1a9b6bd

Browse files
committed
(fix) handle point updates are not reflected
1 parent f1c311d commit 1a9b6bd

8 files changed

+173
-42
lines changed

.coverage

0 Bytes
Binary file not shown.

server.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
app = Flask(__name__)
66
app.secret_key = "something_special"
7+
app.config["CLUB_FILE"] = "clubs.json"
78
app.config["COMPETITIONS_FILE"] = "competitions.json"
89

910

1011
def loadClubs():
11-
with open("clubs.json") as c:
12+
with open(app.config["CLUB_FILE"]) as c:
1213
listOfClubs = json.load(c)["clubs"]
1314
return listOfClubs
1415

@@ -96,6 +97,10 @@ def get_club_from_name(name):
9697
return None
9798

9899

100+
def get_index_club(club):
101+
return clubs.index(club)
102+
103+
99104
def check_places(places, club):
100105
if not places or int(places) < 1:
101106
return "Places required must be a positive integer"
@@ -119,20 +124,32 @@ def take_places(places, club, competition):
119124
return False
120125

121126

127+
def update_clubs(club, index_club):
128+
try:
129+
with open(app.config["CLUB_FILE"], "w") as file_club:
130+
dict_clubs = {}
131+
clubs[index_club]["points"] = str(club["points"])
132+
dict_clubs["clubs"] = clubs
133+
json.dump(dict_clubs, file_club, indent=4)
134+
return True
135+
except FileNotFoundError:
136+
return False
137+
138+
122139
@app.route("/purchasePlaces", methods=["POST"])
123140
def purchasePlaces():
124141
competition = get_competition_from_name(request.form["competition"])
125142
club = get_club_from_name(request.form["club"])
126-
127143
error_message = check_places(request.form["places"], club)
128144
if error_message:
129145
flash(error_message)
130146
return redirect(
131147
url_for("book", competition=competition["name"], club=club["name"])
132148
)
133149
placesRequired = int(request.form["places"])
134-
135-
if take_places(placesRequired, club, competition):
150+
if take_places(placesRequired, club, competition) and update_clubs(
151+
club, get_index_club(club)
152+
):
136153
flash("Great-booking complete!")
137154
return render_template(
138155
"welcome.html", club=club, competitions=competitions

tests/integration_tests/conftest.py

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
1+
import builtins
12
import json
3+
import os
4+
import tempfile
25
import pytest
36
from unittest.mock import mock_open, patch
47

8+
9+
clubs_list = [
10+
{"name": "Club 1", "email": "club1@example.com", "points": "10"},
11+
{"name": "Club 2", "email": "club2@example.com", "points": "15"},
12+
]
13+
14+
competitions_list = [
15+
{
16+
"name": "Competition 1",
17+
"date": "2023-03-27 10:00:00",
18+
"numberOfPlaces": "25",
19+
},
20+
{
21+
"name": "Competition 2",
22+
"date": "2023-10-22 13:30:00",
23+
"numberOfPlaces": "15",
24+
},
25+
]
26+
27+
528
# Mock data for clubs.json and competitions.json
6-
mock_clubs_json = json.dumps({
7-
"clubs": [
8-
{"name": "Club 1", "email": "club1@example.com", "points": "10"},
9-
{"name": "Club 2", "email": "club2@example.com", "points": "15"}
10-
]
11-
})
12-
13-
mock_competitions_json = json.dumps({
14-
"competitions": [
15-
{"name": "Competition 1", "date": "2023-03-27 10:00:00",
16-
"numberOfPlaces": "25"},
17-
{"name": "Competition 2", "date": "2023-10-22 13:30:00",
18-
"numberOfPlaces": "15"}
19-
]
20-
})
29+
mock_clubs_json = json.dumps({"clubs": clubs_list})
30+
31+
mock_competitions_json = json.dumps({"competitions": competitions_list})
2132

2233

2334
def mocked_open(file, *args, **kwargs):
@@ -30,17 +41,45 @@ def mocked_open(file, *args, **kwargs):
3041
elif file == "competitions.json":
3142
return mock_open(read_data=mock_competitions_json)()
3243
else:
33-
raise FileNotFoundError(f"File {file} not found")
44+
return builtins.open(file, *args, **kwargs)
3445

3546

3647
# Patch open before importing the app to ensure clubs
3748
# and competitions are loaded with mock data
3849
with patch("builtins.open", side_effect=mocked_open):
39-
from server import app # Import app after patching
50+
from server import app # noqa
51+
52+
53+
@pytest.fixture
54+
def temp_clubs_file():
55+
"""
56+
Create a temporary directory and file for clubs.json
57+
"""
58+
with tempfile.TemporaryDirectory() as temp_dir:
59+
temp_club_file_path = os.path.join(temp_dir, "clubs.json")
60+
61+
# Create a temporary clubs.json file
62+
clubs_data = {
63+
"clubs": clubs_list,
64+
}
65+
66+
with open(temp_club_file_path, "w") as f:
67+
json.dump(clubs_data, f, indent=4)
68+
69+
# Yield the path to the file for the tests
70+
yield temp_club_file_path
4071

4172

4273
@pytest.fixture
43-
def client():
74+
def client(temp_clubs_file):
75+
"""
76+
Set up the Flask test client and override the CLUB_FILE config
77+
with the temporary file.
78+
"""
4479
app.config["TESTING"] = True
80+
app.config[
81+
"CLUB_FILE"
82+
] = temp_clubs_file # Override with temp clubs.json path
83+
4584
with app.test_client() as client:
4685
yield client

tests/integration_tests/test_clubs_should_not_use_more_than_their_points.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11

2-
32
def test_purchase_places_valid(client):
43
"""
54
Test purchasing places with valid club points and valid competition.
65
"""
7-
response = client.post("/purchasePlaces", data={
8-
"competition": "Competition 1",
9-
"club": "Club 1",
10-
"places": "5"
11-
})
6+
response = client.post(
7+
"/purchasePlaces",
8+
data={"competition": "Competition 1", "club": "Club 1", "places": "5"},
9+
)
1210

1311
assert response.status_code == 200
1412
assert b"Great-booking complete!" in response.data
@@ -18,11 +16,14 @@ def test_purchase_places_insufficient_points(client):
1816
"""
1917
Test purchasing more places than the club's available points.
2018
"""
21-
response = client.post("/purchasePlaces", data={
22-
"competition": "Competition 1",
23-
"club": "Club 1",
24-
"places": "11" # Club 1 has only 10 points
25-
})
19+
response = client.post(
20+
"/purchasePlaces",
21+
data={
22+
"competition": "Competition 1",
23+
"club": "Club 1",
24+
"places": "11", # Club 1 has only 10 points
25+
},
26+
)
2627

2728
assert response.status_code == 302 # Redirect expected
2829
response = client.get(response.headers["Location"]) # Follow the redirect
@@ -33,11 +34,10 @@ def test_purchase_places_zero_places(client):
3334
"""
3435
Test purchasing zero places, which is an invalid input.
3536
"""
36-
response = client.post("/purchasePlaces", data={
37-
"competition": "Competition 1",
38-
"club": "Club 1",
39-
"places": "0"
40-
})
37+
response = client.post(
38+
"/purchasePlaces",
39+
data={"competition": "Competition 1", "club": "Club 1", "places": "0"},
40+
)
4141

4242
assert response.status_code == 302 # Redirect expected
4343
response = client.get(response.headers["Location"]) # Follow the redirect
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import json
2+
3+
4+
def test_purchase_places_valid(client):
5+
"""
6+
Test purchasing places with valid club points and valid competition.
7+
"""
8+
response = client.post("/purchasePlaces", data={
9+
"competition": "Competition 1",
10+
"club": "Club 1",
11+
"places": "5"
12+
})
13+
14+
# Check the response and verify the club's points were updated
15+
assert response.status_code == 200
16+
assert b"Great-booking complete!" in response.data
17+
18+
with open(client.application.config['CLUB_FILE'], 'r') as f:
19+
updated_clubs = json.load(f)
20+
assert updated_clubs["clubs"][0]["points"] == "0"

tests/unit_tests/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,11 @@
66
def client():
77
with app.test_client() as client:
88
yield client
9+
10+
11+
@pytest.fixture
12+
def mock_clubs_fixture():
13+
return [
14+
{"name": "Club 1", "email": "club1@example.com", "points": "10"},
15+
{"name": "Club 2", "email": "club2@example.com", "points": "15"},
16+
]

tests/unit_tests/test_clubs_should_not_use_more_than_their_points.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,30 +87,37 @@ def test_take_places_invalid():
8787

8888

8989
# Unit test for valid booking
90+
9091
@patch("server.competitions", mock_competitions_list)
9192
@patch("server.render_template")
93+
@patch("server.update_clubs")
9294
@patch("server.take_places")
9395
@patch("server.check_places")
96+
@patch("server.get_index_club")
9497
@patch("server.get_club_from_name")
9598
@patch("server.get_competition_from_name")
9699
@patch("server.flash")
97100
def test_purchase_places_valid(
98101
mock_flash,
99102
mock_get_competition,
100103
mock_get_club,
104+
mock_get_index_club,
101105
mock_check_places,
102106
mock_take_places,
107+
mock_update_clubs,
103108
mock_render_template,
104109
client,
105110
):
106111
# Mock the functions to return valid data
107112
mock_get_competition.return_value = mock_competitions_list[0]
108113
mock_get_club.return_value = mock_clubs_list[0]
114+
mock_get_index_club.return_value = 0
109115
mock_check_places.return_value = None # No error message
110116
mock_take_places.return_value = True # Simulate successful booking
117+
mock_update_clubs.return_value = True
111118

112119
# Simulate POST request to the route
113-
response = client.post(
120+
client.post(
114121
"/purchasePlaces",
115122
data={"competition": "Competition 1", "club": "Club 1", "places": "5"},
116123
)
@@ -129,9 +136,6 @@ def test_purchase_places_valid(
129136
competitions=mock_competitions_list,
130137
)
131138

132-
# Check response status code
133-
assert response.status_code == 200
134-
135139

136140
# Unit test for booking with error in places
137141
@patch("server.redirect")
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from unittest.mock import mock_open, patch
2+
from server import update_clubs, get_index_club
3+
4+
5+
def test_get_index_club(mock_clubs_fixture):
6+
# Test finding the index of a club
7+
with patch("server.clubs", mock_clubs_fixture):
8+
club = mock_clubs_fixture[0]
9+
index = get_index_club(club)
10+
assert index == 0
11+
12+
13+
@patch("builtins.open", new_callable=mock_open)
14+
@patch("json.dump")
15+
def test_update_clubs_success(mock_json_dump, mock_file, mock_clubs_fixture):
16+
club = {"name": "Club 1", "points": "20"}
17+
index = 0
18+
with patch("server.clubs", mock_clubs_fixture):
19+
result = update_clubs(club, index)
20+
21+
assert result is True
22+
assert mock_clubs_fixture[0]["points"] == "20"
23+
mock_json_dump.assert_called_once()
24+
mock_file.assert_called_once()
25+
26+
27+
@patch("builtins.open", side_effect=FileNotFoundError)
28+
def test_update_clubs_file_not_found(mock_file, mock_clubs_fixture):
29+
# Club to be updated
30+
club = {"name": "Club 1", "points": "20"}
31+
index = 0
32+
33+
# Test update_clubs when FileNotFoundError is raised
34+
with patch("server.clubs", mock_clubs_fixture):
35+
result = update_clubs(club, index)
36+
37+
# Assert that the function returns False
38+
assert result is False
39+
40+
# Assert that no changes were made to the clubs list
41+
assert (
42+
mock_clubs_fixture[0]["points"] == "10"
43+
) # The points shouldn't be updated

0 commit comments

Comments
 (0)