Import existing LinTunes project
Snapshot of the existing codebase before working through the TASKS.md backlog. Real library data (data/) and the iTunes import fixture (itunes-test-library/) are gitignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
175
tests/test_models.py
Normal file
175
tests/test_models.py
Normal file
@ -0,0 +1,175 @@
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from lintunes.models import Track, Playlist, PlaylistSettings, PlaylistType, Library
|
||||
|
||||
|
||||
class TestTrack:
|
||||
def test_to_dict_omits_defaults(self):
|
||||
track = Track(track_id=1, name="Test Song")
|
||||
d = track.to_dict()
|
||||
assert d == {"track_id": 1, "name": "Test Song"}
|
||||
assert "genre" not in d
|
||||
assert "play_count" not in d
|
||||
|
||||
def test_from_dict_round_trip(self):
|
||||
track = Track(
|
||||
track_id=42,
|
||||
name="My Song",
|
||||
artist="The Artist",
|
||||
album="The Album",
|
||||
genre="Rock",
|
||||
total_time=180000,
|
||||
play_count=5,
|
||||
rating=80,
|
||||
loved=True,
|
||||
date_added="2020-01-15T10:30:00",
|
||||
)
|
||||
d = track.to_dict()
|
||||
restored = Track.from_dict(d)
|
||||
assert restored.track_id == 42
|
||||
assert restored.name == "My Song"
|
||||
assert restored.artist == "The Artist"
|
||||
assert restored.play_count == 5
|
||||
assert restored.rating == 80
|
||||
assert restored.loved is True
|
||||
|
||||
def test_from_dict_ignores_unknown_fields(self):
|
||||
d = {"track_id": 1, "name": "Test", "unknown_field": "ignored"}
|
||||
track = Track.from_dict(d)
|
||||
assert track.track_id == 1
|
||||
assert track.name == "Test"
|
||||
|
||||
def test_from_itunes_dict(self):
|
||||
itunes_data = {
|
||||
"Track ID": 100,
|
||||
"Name": "iTunes Song",
|
||||
"Artist": "iTunes Artist",
|
||||
"Album": "iTunes Album",
|
||||
"Genre": "Pop",
|
||||
"Total Time": 240000,
|
||||
"Play Count": 10,
|
||||
"Play Date UTC": datetime(2023, 6, 15, 12, 0, 0),
|
||||
"Date Added": datetime(2020, 3, 1, 8, 0, 0),
|
||||
"Rating": 100,
|
||||
"Loved": True,
|
||||
"Persistent ID": "ABC123",
|
||||
"Location": "file://localhost/Users/me/Music/Artist/Album/Song.mp3",
|
||||
}
|
||||
track = Track.from_itunes_dict(itunes_data)
|
||||
assert track.track_id == 100
|
||||
assert track.name == "iTunes Song"
|
||||
assert track.total_time == 240000
|
||||
assert track.play_count == 10
|
||||
assert track.rating == 100
|
||||
assert track.loved is True
|
||||
assert track.play_date_utc == "2023-06-15T12:00:00"
|
||||
assert track.location == "/Users/me/Music/Artist/Album/Song.mp3"
|
||||
|
||||
def test_location_decoding(self):
|
||||
itunes_data = {
|
||||
"Track ID": 1,
|
||||
"Location": "file://localhost/Users/me/Music/The%20Artist/My%20Album/01%20Song.mp3",
|
||||
}
|
||||
track = Track.from_itunes_dict(itunes_data)
|
||||
assert track.location == "/Users/me/Music/The Artist/My Album/01 Song.mp3"
|
||||
|
||||
def test_location_decoding_volumes_form(self):
|
||||
# Modern iTunes XML uses file:///Volumes/... URLs
|
||||
itunes_data = {
|
||||
"Track ID": 1,
|
||||
"Location": "file:///Volumes/Lucia/iTunes/iTunes%20Media/Music/A/B/C.m4a",
|
||||
}
|
||||
track = Track.from_itunes_dict(itunes_data)
|
||||
assert track.location == "/Volumes/Lucia/iTunes/iTunes Media/Music/A/B/C.m4a"
|
||||
|
||||
|
||||
class TestPlaylist:
|
||||
def test_to_dict_from_dict_round_trip(self):
|
||||
playlist = Playlist(
|
||||
name="My Favorites",
|
||||
persistent_id="ABCD1234",
|
||||
playlist_type=PlaylistType.REGULAR,
|
||||
track_ids=[1, 2, 3, 4, 5],
|
||||
)
|
||||
d = playlist.to_dict()
|
||||
restored = Playlist.from_dict(d)
|
||||
assert restored.name == "My Favorites"
|
||||
assert restored.persistent_id == "ABCD1234"
|
||||
assert restored.playlist_type == PlaylistType.REGULAR
|
||||
assert restored.track_ids == [1, 2, 3, 4, 5]
|
||||
|
||||
def test_from_itunes_dict_regular(self):
|
||||
itunes_data = {
|
||||
"Name": "Party Mix",
|
||||
"Playlist Persistent ID": "XYZ789",
|
||||
"Playlist Items": [
|
||||
{"Track ID": 10},
|
||||
{"Track ID": 20},
|
||||
{"Track ID": 30},
|
||||
],
|
||||
}
|
||||
playlist = Playlist.from_itunes_dict(itunes_data)
|
||||
assert playlist.name == "Party Mix"
|
||||
assert playlist.persistent_id == "XYZ789"
|
||||
assert playlist.playlist_type == PlaylistType.REGULAR
|
||||
assert playlist.track_ids == [10, 20, 30]
|
||||
assert playlist.is_system is False
|
||||
|
||||
def test_from_itunes_dict_system(self):
|
||||
itunes_data = {
|
||||
"Name": "Library",
|
||||
"Master": True,
|
||||
"Playlist Persistent ID": "MASTER1",
|
||||
"Playlist Items": [{"Track ID": 1}],
|
||||
}
|
||||
playlist = Playlist.from_itunes_dict(itunes_data)
|
||||
assert playlist.is_system is True
|
||||
assert playlist.playlist_type == PlaylistType.SYSTEM
|
||||
|
||||
def test_from_itunes_dict_folder(self):
|
||||
itunes_data = {
|
||||
"Name": "My Folder",
|
||||
"Folder": True,
|
||||
"Playlist Persistent ID": "FOLDER1",
|
||||
}
|
||||
playlist = Playlist.from_itunes_dict(itunes_data)
|
||||
assert playlist.playlist_type == PlaylistType.FOLDER
|
||||
|
||||
def test_from_itunes_dict_smart(self):
|
||||
itunes_data = {
|
||||
"Name": "Recently Added",
|
||||
"Smart Info": b"...",
|
||||
"Smart Criteria": b"...",
|
||||
"Playlist Persistent ID": "SMART1",
|
||||
}
|
||||
playlist = Playlist.from_itunes_dict(itunes_data)
|
||||
assert playlist.playlist_type == PlaylistType.SMART
|
||||
|
||||
|
||||
class TestPlaylistSettings:
|
||||
def test_default_settings(self):
|
||||
settings = PlaylistSettings()
|
||||
assert "name" in settings.visible_columns
|
||||
assert settings.sort_ascending is True
|
||||
|
||||
def test_round_trip(self):
|
||||
settings = PlaylistSettings(
|
||||
visible_columns=["name", "artist"],
|
||||
sort_column="artist",
|
||||
sort_ascending=False,
|
||||
column_widths={"name": 300},
|
||||
)
|
||||
d = settings.to_dict()
|
||||
restored = PlaylistSettings.from_dict(d)
|
||||
assert restored.visible_columns == ["name", "artist"]
|
||||
assert restored.sort_column == "artist"
|
||||
assert restored.sort_ascending is False
|
||||
assert restored.column_widths == {"name": 300}
|
||||
|
||||
|
||||
class TestLibrary:
|
||||
def test_empty_library(self):
|
||||
lib = Library()
|
||||
assert len(lib.tracks) == 0
|
||||
assert len(lib.playlists) == 0
|
||||
Reference in New Issue
Block a user