"""Tests for helper functions in the GUI module (gui.py).""" import json import pytest # ── _fmt_ms ─────────────────────────────────────────────────────────────────── class TestFmtMs: """Tests for the _fmt_ms helper.""" def _import(self): from gui import _fmt_ms return _fmt_ms def test_zero(self): fn = self._import() assert fn(0) == "0:00" def test_seconds_only(self): fn = self._import() assert fn(5_000) == "0:05" assert fn(59_000) == "0:59" def test_minutes(self): fn = self._import() assert fn(60_000) == "1:00" assert fn(90_000) == "1:30" assert fn(3599_000) == "59:59" def test_hours_display(self): fn = self._import() assert fn(3600_000) == "60:00" assert fn(3661_000) == "61:01" def test_large_duration(self): fn = self._import() assert fn(5999_000) == "99:59" # ── _artists_str ───────────────────────────────────────────────────────────── class TestArtistsStr: """Tests for the _artists_str helper.""" def _import(self): from gui import _artists_str return _artists_str def test_none(self): fn = self._import() assert fn(None) == "" def test_empty_list(self): fn = self._import() assert fn([]) == "" def test_not_a_list(self): fn = self._import() assert fn("str") == "" assert fn(42) == "" def test_single_artist(self): fn = self._import() assert fn([{"name": "Artist One", "id": "a1"}]) == "Artist One" def test_multiple_artists(self): fn = self._import() artists = [ {"name": "Artist One", "id": "a1"}, {"name": "Artist Two", "id": "a2"}, ] assert fn(artists) == "Artist One, Artist Two" def test_artist_without_name_key(self): fn = self._import() assert fn([{"id": "a1"}]) == "" def test_mixed_valid_and_invalid(self): fn = self._import() artists = [ {"name": "Valid", "id": "v1"}, {"id": "no_name"}, {"name": "Also Valid", "id": "v2"}, ] assert fn(artists) == "Valid, Also Valid" # ── _norm_artists ──────────────────────────────────────────────────────────── class TestNormArtists: """Tests for the _norm_artists helper.""" def _import(self): from gui import _norm_artists return _norm_artists def test_none(self): fn = self._import() assert fn(None) == [] def test_not_a_list(self): fn = self._import() assert fn("not a list") == [] assert fn(42) == [] def test_empty_list(self): fn = self._import() assert fn([]) == [] def test_filters_non_dicts(self): fn = self._import() artists = [{"name": "Real"}, "just a string", 123, {"name": "Another"}] result = fn(artists) assert len(result) == 2 assert result[0]["name"] == "Real" assert result[1]["name"] == "Another" def test_all_valid(self): fn = self._import() artists = [{"name": "A"}, {"name": "B"}] assert fn(artists) == artists # ── _artists_from_json ─────────────────────────────────────────────────────── class TestArtistsFromJson: """Tests for the _artists_from_json helper.""" def _import(self): from gui import _artists_from_json return _artists_from_json def test_valid_json_array(self): fn = self._import() j = json.dumps([{"name": "Artist A", "id": "a1"}, {"name": "Artist B", "id": "a2"}]) assert fn(j) == "Artist A, Artist B" def test_single_artist_json(self): fn = self._import() j = json.dumps([{"name": "Solo Artist", "id": "s1"}]) assert fn(j) == "Solo Artist" def test_invalid_json(self): fn = self._import() assert fn("not json") == "not json" def test_empty_array(self): fn = self._import() assert fn("[]") == "" def test_plain_string_input(self): fn = self._import() assert fn("Just a name") == "Just a name" def test_jagged_array_skips_non_dicts(self): fn = self._import() j = json.dumps([{"name": "Real"}, 42, "str", {"name": "Also Real"}]) assert fn(j) == "Real, Also Real" # ── _css ─────────────────────────────────────────────────────────────────── class TestCss: """Tests for the _css helper.""" def _import(self): from gui import _css return _css def test_joins_multiple_parts(self): fn = self._import() assert fn("color: red;", "background: blue;") == "color: red;background: blue;" def test_single_part(self): fn = self._import() assert fn("color: red;") == "color: red;" def test_empty_parts(self): fn = self._import() assert fn() == "" # ── _get_thumbnail_nam ──────────────────────────────────────────────────── class TestGetThumbnailNam: """Tests for the _get_thumbnail_nam helper.""" def _import(self): from gui import _get_thumbnail_nam return _get_thumbnail_nam def test_returns_network_access_manager(self): fn = self._import() nam = fn() # Should return some kind of object (QNetworkAccessManager or MagicMock) assert nam is not None def test_is_singleton(self): fn = self._import() nam1 = fn() nam2 = fn() assert nam1 is nam2 # ── _cached_thumb_path ──────────────────────────────────────────────────── class TestCachedThumbPath: """Tests for the _cached_thumb_path helper.""" def _import(self): from gui import _cached_thumb_path, THUMB_CACHE_DIR return _cached_thumb_path, THUMB_CACHE_DIR def test_uses_cache_dir(self): fn, cache_dir = self._import() path = fn("video123") assert str(path) == str(cache_dir / "video123.jpg") def test_ends_with_jpg(self): fn, _ = self._import() path = fn("abc_def") assert path.suffix == ".jpg" assert "abc_def" in path.name