Files

169 lines
5.1 KiB
Python

from datetime import timedelta
from app import db
from app.models.gamestate import GameState
from app.models.login_attempt import LoginAttempt
from app.models.user import User
from app.routes.login_routes import utcnow
def test_dashboard_requires_login(client):
response = client.get("/dashboard")
assert response.status_code == 302
assert "/login" in response.headers["Location"]
def test_register_creates_user_and_redirects_to_login(client, app_instance):
response = client.post(
"/register",
data={"username": "newuser", "password": "Password123!"},
follow_redirects=False,
)
assert response.status_code == 302
assert "/login" in response.headers["Location"]
with app_instance.app_context():
saved_user = User.query.filter_by(username="newuser").first()
assert saved_user is not None
def test_login_blocks_requests_from_a_locked_ip(client, app_instance, user_factory):
user_factory(username="lockeduser", password="Password123!")
with app_instance.app_context():
db.session.add(
LoginAttempt(
ip_address="203.0.113.10",
failed_attempts=4,
locked_until=utcnow() + timedelta(minutes=5),
)
)
db.session.commit()
response = client.post(
"/login",
data={"username": "lockeduser", "password": "Password123!"},
headers={"X-Forwarded-For": "203.0.113.10"},
)
assert response.status_code == 200
assert b"Too many failed login attempts" in response.data
def test_check_endpoint_applies_different_rules_for_queens_and_rooks(client):
board = [
[1, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
]
queens_response = client.post(
"/check",
json={"board": board, "row": 1, "col": 1, "mode": "queens"},
)
rooks_response = client.post(
"/check",
json={"board": board, "row": 1, "col": 1, "mode": "rooks"},
)
assert queens_response.status_code == 200
assert rooks_response.status_code == 200
assert queens_response.get_json() == {"valid": False}
assert rooks_response.get_json() == {"valid": True}
def test_solve_endpoint_returns_one_valid_4x4_queens_solution(client):
response = client.get("/solve?size=4")
assert response.status_code == 200
assert tuple(response.get_json()) in {
(1, 3, 0, 2),
(2, 0, 3, 1),
}
def test_authenticated_user_can_save_and_load_a_game_state(client, app_instance, user_factory, login_as):
user_factory(username="alice", password="Password123!")
login_response = login_as("alice", "Password123!")
assert login_response.status_code == 302
payload = {
"board": [
[0, 1, 0, 0],
[0, 0, 0, 1],
[1, 0, 0, 0],
[0, 0, 1, 0],
],
"mode": "queens",
"boardSize": 4,
"saveName": "test-save",
"saveNote": "unit integration save",
"isFavorite": False,
"stepCount": 7,
"elapsedSeconds": 42,
"isSolved": True,
}
save_response = client.post("/save", json=payload)
assert save_response.status_code == 200
saved_data = save_response.get_json()["save_point"]
load_response = client.get(f"/load/{saved_data['id']}")
assert load_response.status_code == 200
loaded_data = load_response.get_json()
assert loaded_data["board"] == payload["board"]
assert loaded_data["mode"] == payload["mode"]
assert loaded_data["step_count"] == payload["stepCount"]
assert loaded_data["elapsed_seconds"] == payload["elapsedSeconds"]
assert loaded_data["is_solved"] is True
with app_instance.app_context():
assert GameState.query.count() == 1
def test_favorite_toggle_changes_filtered_save_point_list(client, user_factory, login_as):
user_factory(username="favuser", password="Password123!")
login_response = login_as("favuser", "Password123!")
assert login_response.status_code == 302
save_response = client.post(
"/save",
json={
"board": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
],
"mode": "rooks",
"boardSize": 4,
"saveName": "favorite-candidate",
"saveNote": "",
"isFavorite": False,
"stepCount": 2,
"elapsedSeconds": 5,
"isSolved": False,
},
)
save_id = save_response.get_json()["save_point"]["id"]
filtered_before = client.get("/save_points?favorites_only=true")
assert filtered_before.status_code == 200
assert filtered_before.get_json() == []
toggle_response = client.post(f"/save_points/{save_id}/favorite")
assert toggle_response.status_code == 200
assert toggle_response.get_json()["is_favorite"] is True
filtered_after = client.get("/save_points?favorites_only=true")
assert filtered_after.status_code == 200
assert len(filtered_after.get_json()) == 1
assert filtered_after.get_json()[0]["id"] == save_id