minor bugfixes and impromvements

This commit is contained in:
eclipse 2025-07-25 12:25:06 +02:00
parent 1adafc1fc7
commit 65cf19f2c4
5 changed files with 40 additions and 35 deletions

View File

@ -5,7 +5,7 @@ from the_works.database import db as _db
TEST_DATABASE_URI = "sqlite:///:memory:"
@pytest.fixture()
def app():
def _app():
test_config = {
"ENV": "Testing",
"SQLALCHEMY_DATABASE_URI": TEST_DATABASE_URI,

View File

@ -1,12 +1,12 @@
from sqlalchemy import select
from the_works.database import db
from the_works.models import Genre
from sqlalchemy.exc import IntegrityError
import pytest
from the_works.database import db
from the_works.models import Genre
def test_genre_create(client, app):
def test_genre_create(client, _app):
"""Integrated testing of adding a Genre record."""
response = client.post("/genre/create", data={"form_Genre": "Test-Genre"}, follow_redirects=True)
response = client.post("/genre/create", data={"form_Genre": "spam"}, follow_redirects=True)
# assert there was exactly 1 redirect
assert len(response.history) == 1
@ -15,13 +15,12 @@ def test_genre_create(client, app):
assert response.status_code == 200
# assert record was successfully added to DB
with app.app_context():
genre = db.session.scalars(select(Genre).where(Genre.Genre == "Test-Genre")).all()
with _app.app_context():
genre = db.session.scalars(select(Genre).where(Genre.Genre == "spam")).all()
assert len(genre) == 1
assert isinstance(genre[0], Genre)
# assert uniqueness of records
with pytest.raises(IntegrityError) as excinfo:
response = client.post("/genre/create", data={"form_Genre": "Test-Genre"})
response = client.post("/genre/create", data={"form_Genre": "spam"})
assert "UNIQUE constraint failed" in str(excinfo.value)

View File

@ -1,17 +1,16 @@
from the_works.models import Genre
import pytest
from the_works.models import Genre
def test_genre_all(client, mocker):
"""Test view all() from genre.py."""
# mock database function
# Note: The original method returns an sqlalchemy.engine.Result.ScalarResult, not a list, but the template code
# uses the return value in a way that works for both ScalarResult and list
# mocker.patch("the_works.database.db.session.scalars", return_value=[
mocker.patch("flask_sqlalchemy.SQLAlchemy.session.scalars", return_value=[
Genre(ID=4, Genre="bla"),
Genre(ID=26, Genre="blubb")
# Note: The original scalars() method returns an sqlalchemy.engine.Result.ScalarResult, not a list
# but the template code uses the return value in a way which works for both ScalarResult and list
mocker.patch("flask_sqlalchemy.session.Session.scalars", return_value=[
Genre(ID=4, Genre="spam"),
Genre(ID=26, Genre="eggs")
])
# test case: get request
@ -28,10 +27,10 @@ def test_genre_create(client, mocker):
"""Test view create() from genre.py."""
# mock database function
mocker.patch("flask_sqlalchemy.SQLAlchemy.session.add")
mocker.patch("flask_sqlalchemy.session.Session.add")
# test a POST request with good data
response = client.post("/genre/create", data={"form_Genre": "Testname"}, follow_redirects=True)
response = client.post("/genre/create", data={"form_Genre": "spam"}, follow_redirects=True)
# exactly 1 redirect
assert len(response.history) == 1
# redirect to the right page
@ -45,7 +44,7 @@ def test_genre_create(client, mocker):
# test a POST request with bad form data
with pytest.raises(ValueError) as excinfo:
response = client.post("/genre/create", data={"wrong_key": "Genrename"})
response = client.post("/genre/create", data={"wrong_key": "eggs"})
assert "value can't be empty" in str(excinfo.value)
# test a POST request with empty form data
@ -54,6 +53,6 @@ def test_genre_create(client, mocker):
assert "value can't be empty" in str(excinfo.value)
# test a GET request
response = client.get("/genre/create", query_string={"form_Genre": "GET-Genre"})
response = client.get("/genre/create", query_string={"form_Genre": "spam eggs"})
assert response.status_code == 405

View File

@ -1,4 +1,12 @@
def test_home_startpage(client):
"""Test view startpage() from home.py."""
response = client.get("/")
# assert good status code
assert response.status_code == 200
# assert that the returned data is good HTML
assert response.data.startswith(b"<!DOCTYPE html>\n")
# more test cases: POST,

View File

@ -1,22 +1,21 @@
import inspect
from flask import Blueprint, render_template, request, jsonify
from sqlalchemy import select
from the_works.database import db
import the_works.models
import inspect
bp = Blueprint("home", __name__)
# prepare list of ORM classes to be searched by search_all()
tables = []
for name, obj in inspect.getmembers(the_works.models):
if inspect.isclass(obj) and issubclass(obj, the_works.models.Base) and obj.__name__ != "Base":
tables.append(obj)
print(f"tables is {tables}") #DEBUG
def __tables():
return [obj for name, obj in inspect.getmembers(the_works.models) if inspect.isclass(obj) and issubclass(obj, the_works.models.Base) and obj.__name__ != "Base"]
@bp.route("/")
def startpage():
return render_template("views/home.html")
@bp.route("/search")
def search_all():
# return when query is empty
@ -29,8 +28,8 @@ def search_all():
result = {}
# loop over database tables
for table in tables:
text_columns = [column.key for column in table.__table__.columns if type(column.type) == db.types.TEXT]
for table in __tables():
text_columns = [column.key for column in table.__table__.columns if isinstance(column.type, db.types.TEXT)]
hits = []
# loop over table rows
for row in db.session.execute(select(table)):
@ -46,7 +45,7 @@ def search_all():
if s.lower() in row[0].__getattribute__(column).lower():
hits.append(row[0].asdict())
break
if hits != []:
if hits:
result[table.__table__.fullname] = hits
# return results
return jsonify(result)