"""Tests for helper functions in the player module (player.py).""" import os import struct import math import tempfile from pathlib import Path import pytest # ── _best_thumbnail ─────────────────────────────────────────────────────────── class TestBestThumbnail: """Tests for the _best_thumbnail helper.""" def _import(self): from player import _best_thumbnail return _best_thumbnail def test_none_or_empty(self): fn = self._import() assert fn(None) == "" assert fn([]) == "" def test_string_returned_as_is(self): fn = self._import() assert fn("https://example.com/thumb.jpg") == "https://example.com/thumb.jpg" def test_list_returns_last_url(self): fn = self._import() thumbs = [ {"url": "https://example.com/small.jpg"}, {"url": "https://example.com/medium.jpg"}, {"url": "https://example.com/large.jpg"}, ] assert fn(thumbs) == "https://example.com/large.jpg" def test_list_without_url_keys(self): fn = self._import() thumbs = [{"width": 100}, {"width": 200}] assert fn(thumbs) == "" def test_list_with_non_dict_items(self): fn = self._import() assert fn(["string_thumb"]) == "string_thumb" def test_non_list_non_string(self): fn = self._import() assert fn(123) == "123" # ── _build_song_dict ───────────────────────────────────────────────────────── class TestBuildSongDict: """Tests for the _build_song_dict helper.""" def _import(self): from player import _build_song_dict return _build_song_dict def test_minimal_result(self): fn = self._import() result = {"videoId": "abc123", "title": "Test Song"} song = fn(result) assert song["videoId"] == "abc123" assert song["title"] == "Test Song" assert song["artists"] == [] assert song["album"] is None assert song["duration"] == 0 assert song["duration_label"] == "?" assert song["thumbnail"] == "" assert song["videoType"] == "" assert song["resultType"] == "song" def test_full_result(self): fn = self._import() result = { "videoId": "xyz789", "title": "Full Song", "artists": [{"name": "Artist", "id": "a1"}], "album": {"name": "Album", "id": "al1"}, "duration_seconds": 300, "duration": "5:00", "thumbnails": [{"url": "https://ex.com/t.jpg"}], "videoType": "MUSIC_VIDEO_TYPE_ATV", "resultType": "video", } song = fn(result) assert song["videoId"] == "xyz789" assert song["title"] == "Full Song" assert song["artists"] == [{"name": "Artist", "id": "a1"}] assert song["album"] == {"name": "Album", "id": "al1"} assert song["duration"] == 300 assert song["duration_label"] == "5:00" assert song["thumbnail"] == "https://ex.com/t.jpg" assert song["videoType"] == "MUSIC_VIDEO_TYPE_ATV" assert song["resultType"] == "video" def test_missing_video_id_defaults_to_empty(self): fn = self._import() song = fn({}) assert song["videoId"] == "" assert song["title"] == "Unknown" assert song["duration"] == 0 def test_thumbnail_from_thumbnails_list(self): fn = self._import() result = { "thumbnails": [ {"url": "https://ex.com/small.jpg"}, {"url": "https://ex.com/large.jpg"}, ] } song = fn(result) assert song["thumbnail"] == "https://ex.com/large.jpg" # ── _generate_test_wav ─────────────────────────────────────────────────────── class TestGenerateTestWav: """Tests for the _generate_test_wav helper.""" def _import(self): from player import _generate_test_wav return _generate_test_wav def test_generates_valid_wav_file(self, tmp_path): """Generated WAV has valid RIFF header and correct size.""" fn = self._import() wav_path = str(tmp_path / "test.wav") fn(wav_path, duration_s=1) with open(wav_path, "rb") as f: data = f.read() # RIFF header assert data[:4] == b"RIFF" assert data[8:12] == b"WAVE" assert data[12:16] == b"fmt " # PCM format (audio_format, num_channels, sample_rate, byte_rate, block_align, bits_per_sample) = struct.unpack_from("