from unittest.mock import MagicMock, patch from db import SongRepo, slugify def test_slugify_basic(): assert slugify("Never Gonna Give You Up", "Rick Astley") == "never-gonna-give-you-up-rick-astley" def test_slugify_truncates_long_input(): s = slugify("a" * 200, "b" * 50) assert len(s) <= 80 def test_slugify_strips_punctuation(): assert slugify("Hello, World!", "DJ?") == "hello-world-dj" def _repo_with_mock_client(): client = MagicMock() return SongRepo(client), client def test_get_song_returns_row_or_none(): repo, client = _repo_with_mock_client() client.table.return_value.select.return_value.eq.return_value.maybe_single.return_value.execute.return_value = MagicMock(data={"youtube_id": "abc"}) row = repo.get_song("abc") assert row == {"youtube_id": "abc"} def test_upsert_song_calls_supabase_upsert(): repo, client = _repo_with_mock_client() client.table.return_value.upsert.return_value.execute.return_value = MagicMock(data=[{"youtube_id": "abc"}]) repo.upsert_song({ "youtube_id": "abc", "slug": "x", "title": "T", "artist": "A", "duration_sec": 100, "r2_key": "karaoke/abc.mp3", "thumbnail_url": "https://i.ytimg.com/vi/abc/hqdefault.jpg", "status": "ready", }) client.table.assert_called_with("songs") client.table.return_value.upsert.assert_called_once() def test_create_job_inserts_and_returns_id(): repo, client = _repo_with_mock_client() client.table.return_value.insert.return_value.execute.return_value = MagicMock( data=[{"id": "job-uuid", "youtube_id": "abc", "status": "queued"}] ) jid = repo.create_job("abc") assert jid == "job-uuid" def test_update_job_sets_status_and_error(): repo, client = _repo_with_mock_client() client.table.return_value.update.return_value.eq.return_value.execute.return_value = MagicMock(data=[]) repo.update_job("job-uuid", status="failed_fetch", error="boom") call = client.table.return_value.update.call_args[0][0] assert call["status"] == "failed_fetch" assert call["error"] == "boom" assert "finished_at" in call