Initial Commit
slip slop
This commit is contained in:
commit
064e672ab7
61 changed files with 3504 additions and 0 deletions
188
tests/test_tunes.py
Normal file
188
tests/test_tunes.py
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
"""Tests for /tunes endpoints."""
|
||||
from tests.conftest import AUTH, BAD_AUTH
|
||||
|
||||
|
||||
def create_tune(client, **kwargs):
|
||||
data = {"name": "Cluck Old Hen", "key": "A", **kwargs}
|
||||
r = client.post("/tunes/", json=data, headers=AUTH)
|
||||
assert r.status_code == 201, r.get_json()
|
||||
return r.get_json()
|
||||
|
||||
|
||||
def get_instrument_id(client, name):
|
||||
instruments = client.get("/instruments").get_json()
|
||||
return next(i["id"] for i in instruments if i["name"] == name)
|
||||
|
||||
|
||||
# ── Auth ──────────────────────────────────────────────────────
|
||||
|
||||
class TestAuth:
|
||||
def test_missing_key_rejected_on_write(self, client):
|
||||
r = client.post("/tunes/", json={"name": "Test"})
|
||||
assert r.status_code == 401
|
||||
|
||||
def test_wrong_key_rejected_on_write(self, client):
|
||||
r = client.post("/tunes/", json={"name": "Test"}, headers=BAD_AUTH)
|
||||
assert r.status_code == 401
|
||||
|
||||
def test_reads_are_public(self, client):
|
||||
assert client.get("/tunes/").status_code == 200
|
||||
|
||||
def test_correct_key_accepted_on_write(self, client):
|
||||
r = client.post("/tunes/", json={"name": "Test"}, headers=AUTH)
|
||||
assert r.status_code == 201
|
||||
|
||||
|
||||
# ── Health ────────────────────────────────────────────────────
|
||||
|
||||
class TestHealth:
|
||||
def test_health(self, client):
|
||||
assert client.get("/health").get_json()["status"] == "ok"
|
||||
|
||||
|
||||
# ── Instruments lookup ────────────────────────────────────────
|
||||
|
||||
class TestInstrumentsLookup:
|
||||
def test_list_instruments(self, client):
|
||||
names = [i["name"] for i in client.get("/instruments").get_json()]
|
||||
assert "banjo" in names
|
||||
assert "fiddle" in names
|
||||
|
||||
|
||||
# ── Tune CRUD ─────────────────────────────────────────────────
|
||||
|
||||
class TestTuneCRUD:
|
||||
def test_create_minimal(self, client):
|
||||
tune = create_tune(client)
|
||||
assert tune["name"] == "Cluck Old Hen"
|
||||
assert tune["key"] == "A"
|
||||
assert tune["modal"] is None
|
||||
assert tune["source"] is None
|
||||
assert tune["instruments"] == []
|
||||
assert tune["notes"] == []
|
||||
assert tune["references"] == []
|
||||
|
||||
def test_create_with_instrument(self, client):
|
||||
banjo_id = get_instrument_id(client, "banjo")
|
||||
tuning = client.post("/tunings/", json={"name": "double C"}, headers=AUTH).get_json()
|
||||
tune = create_tune(client, instruments=[{
|
||||
"instrument_id": banjo_id,
|
||||
"tuning_id": tuning["id"],
|
||||
"callable": True,
|
||||
}])
|
||||
assert len(tune["instruments"]) == 1
|
||||
assert tune["instruments"][0]["instrument_name"] == "banjo"
|
||||
assert tune["instruments"][0]["tuning"] == "double C"
|
||||
|
||||
def test_create_with_two_instruments(self, client):
|
||||
banjo_id = get_instrument_id(client, "banjo")
|
||||
fiddle_id = get_instrument_id(client, "fiddle")
|
||||
tune = create_tune(client, instruments=[
|
||||
{"instrument_id": banjo_id, "tuning": "double C"},
|
||||
{"instrument_id": fiddle_id, "tuning": "cross"},
|
||||
])
|
||||
assert len(tune["instruments"]) == 2
|
||||
|
||||
def test_create_with_notes_and_references(self, client):
|
||||
tune = create_tune(client,
|
||||
notes=[{"note": "tricky B part"}],
|
||||
references=[{"link": "https://youtube.com/x", "site": "YouTube"}],
|
||||
)
|
||||
assert tune["notes"][0]["note"] == "tricky B part"
|
||||
assert tune["references"][0]["site"] == "YouTube"
|
||||
|
||||
def test_get_single(self, client):
|
||||
created = create_tune(client)
|
||||
r = client.get(f'/tunes/{created["id"]}', headers=AUTH)
|
||||
assert r.status_code == 200
|
||||
assert r.get_json()["id"] == created["id"]
|
||||
|
||||
def test_get_nonexistent_returns_404(self, client):
|
||||
assert client.get("/tunes/99999", headers=AUTH).status_code == 404
|
||||
|
||||
def test_list_returns_all(self, client):
|
||||
create_tune(client, name="Tune A")
|
||||
create_tune(client, name="Tune B")
|
||||
names = [t["name"] for t in client.get("/tunes/", headers=AUTH).get_json()]
|
||||
assert "Tune A" in names and "Tune B" in names
|
||||
|
||||
def test_patch_core_fields(self, client):
|
||||
tune = create_tune(client)
|
||||
r = client.patch(f'/tunes/{tune["id"]}',
|
||||
json={"key": "G", "name": "New Name", "modal": True},
|
||||
headers=AUTH)
|
||||
assert r.status_code == 200
|
||||
u = r.get_json()
|
||||
assert u["key"] == "G" and u["name"] == "New Name" and u["modal"] is True
|
||||
|
||||
def test_delete(self, client):
|
||||
tune = create_tune(client)
|
||||
r = client.delete(f'/tunes/{tune["id"]}', headers=AUTH)
|
||||
assert r.status_code == 200
|
||||
assert client.get(f'/tunes/{tune["id"]}', headers=AUTH).status_code == 404
|
||||
|
||||
def test_delete_cascades_to_instrument_entry(self, client):
|
||||
from app.models import TuneByInstrument
|
||||
from app.extensions import db
|
||||
banjo_id = get_instrument_id(client, "banjo")
|
||||
tune = create_tune(client, instruments=[{"instrument_id": banjo_id}])
|
||||
client.delete(f'/tunes/{tune["id"]}', headers=AUTH)
|
||||
assert db.session.query(TuneByInstrument).filter_by(tune_id=tune["id"]).count() == 0
|
||||
|
||||
|
||||
# ── Filtering ─────────────────────────────────────────────────
|
||||
|
||||
class TestFiltering:
|
||||
def test_filter_by_key(self, client):
|
||||
create_tune(client, name="D tune", key="D")
|
||||
create_tune(client, name="G tune", key="G")
|
||||
results = client.get("/tunes/?key=D", headers=AUTH).get_json()
|
||||
assert all(t["key"] == "D" for t in results)
|
||||
|
||||
def test_search_by_name(self, client):
|
||||
create_tune(client, name="Whiskey Before Breakfast")
|
||||
create_tune(client, name="Salt Creek")
|
||||
results = client.get("/tunes/?search=whiskey", headers=AUTH).get_json()
|
||||
assert len(results) == 1
|
||||
assert results[0]["name"] == "Whiskey Before Breakfast"
|
||||
|
||||
def test_filter_by_instrument(self, client):
|
||||
banjo_id = get_instrument_id(client, "banjo")
|
||||
create_tune(client, name="Has Banjo",
|
||||
instruments=[{"instrument_id": banjo_id, "tuning": "standard"}])
|
||||
create_tune(client, name="No Banjo")
|
||||
results = client.get(f"/tunes/?instrument_id={banjo_id}", headers=AUTH).get_json()
|
||||
names = [t["name"] for t in results]
|
||||
assert "Has Banjo" in names and "No Banjo" not in names
|
||||
|
||||
def test_filter_by_tuning(self, client):
|
||||
fiddle_id = get_instrument_id(client, "fiddle")
|
||||
cross_tuning = client.post("/tunings/", json={"name": "cross"}, headers=AUTH).get_json()
|
||||
std_tuning = client.post("/tunings/", json={"name": "standard"}, headers=AUTH).get_json()
|
||||
create_tune(client, name="Cross", instruments=[{"instrument_id": fiddle_id, "tuning_id": cross_tuning["id"]}])
|
||||
create_tune(client, name="Std", instruments=[{"instrument_id": fiddle_id, "tuning_id": std_tuning["id"]}])
|
||||
results = client.get(f'/tunes/?instrument_id={fiddle_id}&tuning={cross_tuning["id"]}', headers=AUTH).get_json()
|
||||
assert len(results) == 1 and results[0]["name"] == "Cross"
|
||||
|
||||
def test_filter_callable(self, client):
|
||||
banjo_id = get_instrument_id(client, "banjo")
|
||||
create_tune(client, name="Can call", instruments=[{"instrument_id": banjo_id, "callable": True}])
|
||||
create_tune(client, name="Cannot call", instruments=[{"instrument_id": banjo_id, "callable": False}])
|
||||
results = client.get(f"/tunes/?instrument_id={banjo_id}&callable=true", headers=AUTH).get_json()
|
||||
names = [t["name"] for t in results]
|
||||
assert "Can call" in names and "Cannot call" not in names
|
||||
|
||||
def test_filter_to_learn(self, client):
|
||||
fiddle_id = get_instrument_id(client, "fiddle")
|
||||
create_tune(client, name="To learn", instruments=[{"instrument_id": fiddle_id, "to_learn": True}])
|
||||
create_tune(client, name="Learned", instruments=[{"instrument_id": fiddle_id, "to_learn": False}])
|
||||
results = client.get(f"/tunes/?instrument_id={fiddle_id}&to_learn=true", headers=AUTH).get_json()
|
||||
names = [t["name"] for t in results]
|
||||
assert "To learn" in names and "Learned" not in names
|
||||
|
||||
def test_filter_modal(self, client):
|
||||
create_tune(client, name="Modal", modal=True)
|
||||
create_tune(client, name="Regular", modal=False)
|
||||
results = client.get("/tunes/?modal=true", headers=AUTH).get_json()
|
||||
names = [t["name"] for t in results]
|
||||
assert "Modal" in names and "Regular" not in names
|
||||
Loading…
Add table
Add a link
Reference in a new issue