BeatDebate / tests /models /test_metadata_models.py
SulmanK's picture
Update README and TODO files for improved clarity and organization - Revised the project structure in the README to enhance readability and reflect recent changes, including the addition of new components and services. Updated the TODO file to provide a comprehensive test design plan, outlining key testing strategies and directory structure for better organization. This update aims to streamline future development efforts and facilitate collaboration on the BeatDebate application.
15980e5
Raw
History Blame Contribute Delete
12.6 kB
"""
Tests for metadata models.
Validates data integrity and logic within data models including:
- Unified track creation from LastFM and Spotify sources
- Track metadata merging
- Underground score calculation
"""
import pytest
from datetime import datetime
from unittest.mock import Mock
from src.models.metadata_models import (
UnifiedTrackMetadata,
MetadataSource,
merge_track_metadata
)
from src.api.lastfm_client import TrackMetadata
from src.api.spotify_client import SpotifyTrack
class TestUnifiedTrackMetadata:
"""Test UnifiedTrackMetadata functionality."""
def test_unified_track_from_lastfm(self):
"""Ensures correct mapping from LastFmTrack to UnifiedTrackMetadata."""
# Create mock LastFM track
lastfm_track = TrackMetadata(
name="Paranoid Android",
artist="Radiohead",
mbid="test-mbid-123",
url="https://last.fm/music/Radiohead/_/Paranoid+Android",
tags=["alternative rock", "experimental", "progressive rock"],
similar_tracks=["Exit Music (For a Film)", "Karma Police"],
listeners=500000,
playcount=2000000,
summary="A classic Radiohead track"
)
# Convert to unified metadata
unified_track = UnifiedTrackMetadata.from_lastfm(lastfm_track)
# Verify mapping
assert unified_track.name == "Paranoid Android"
assert unified_track.artist == "Radiohead"
assert unified_track.lastfm_mbid == "test-mbid-123"
assert unified_track.external_urls == {"lastfm": "https://last.fm/music/Radiohead/_/Paranoid+Android"}
assert unified_track.listeners == 500000
assert unified_track.playcount == 2000000
assert unified_track.tags == ["alternative rock", "experimental", "progressive rock"]
assert unified_track.similar_tracks == ["Exit Music (For a Film)", "Karma Police"]
assert unified_track.source == MetadataSource.LASTFM
assert "lastfm" in unified_track.source_data
assert unified_track.source_data["lastfm"]["name"] == "Paranoid Android"
def test_unified_track_from_spotify(self):
"""Ensures correct mapping from SpotifyTrack to UnifiedTrackMetadata."""
# Create mock Spotify track
spotify_track = SpotifyTrack(
id="spotify-track-123",
name="Paranoid Android",
artist="Radiohead",
album="OK Computer",
preview_url="https://p.scdn.co/mp3-preview/123",
external_urls={"spotify": "https://open.spotify.com/track/123"},
duration_ms=383000,
popularity=85
)
# Convert to unified metadata
unified_track = UnifiedTrackMetadata.from_spotify(spotify_track)
# Verify mapping
assert unified_track.name == "Paranoid Android"
assert unified_track.artist == "Radiohead"
assert unified_track.album == "OK Computer"
assert unified_track.spotify_id == "spotify-track-123"
assert unified_track.duration_ms == 383000
assert unified_track.preview_url == "https://p.scdn.co/mp3-preview/123"
assert unified_track.external_urls == {"spotify": "https://open.spotify.com/track/123"}
assert unified_track.popularity == 85
assert unified_track.source == MetadataSource.SPOTIFY
assert "spotify" in unified_track.source_data
assert unified_track.source_data["spotify"]["id"] == "spotify-track-123"
def test_merge_track_metadata(self):
"""Validates that merging two UnifiedTrackMetadata objects correctly combines their data."""
# Create LastFM track
lastfm_track = UnifiedTrackMetadata(
name="Paranoid Android",
artist="Radiohead",
lastfm_mbid="test-mbid-123",
external_urls={"lastfm": "https://last.fm/track/123"},
listeners=500000,
playcount=2000000,
tags=["alternative rock", "experimental"],
source=MetadataSource.LASTFM,
source_data={"lastfm": {"name": "Paranoid Android"}}
)
# Create Spotify track
spotify_track = UnifiedTrackMetadata(
name="Paranoid Android",
artist="Radiohead",
album="OK Computer",
spotify_id="spotify-123",
duration_ms=383000,
preview_url="https://preview.url",
external_urls={"spotify": "https://spotify.com/track/123"},
popularity=85,
tags=["progressive rock"],
source=MetadataSource.SPOTIFY,
source_data={"spotify": {"id": "spotify-123"}}
)
# Merge tracks
merged_track = lastfm_track.merge_with(spotify_track)
# Verify merged data
assert merged_track.name == "Paranoid Android"
assert merged_track.artist == "Radiohead"
assert merged_track.album == "OK Computer" # From Spotify
assert merged_track.spotify_id == "spotify-123" # From Spotify
assert merged_track.lastfm_mbid == "test-mbid-123" # From LastFM
assert merged_track.duration_ms == 383000 # From Spotify
assert merged_track.preview_url == "https://preview.url" # From Spotify
assert merged_track.listeners == 500000 # From LastFM
assert merged_track.playcount == 2000000 # From LastFM
assert merged_track.popularity == 85 # From Spotify
# Verify merged external URLs
assert "lastfm" in merged_track.external_urls
assert "spotify" in merged_track.external_urls
assert merged_track.external_urls["lastfm"] == "https://last.fm/track/123"
assert merged_track.external_urls["spotify"] == "https://spotify.com/track/123"
# Verify merged tags (deduplicated)
expected_tags = {"alternative rock", "experimental", "progressive rock"}
assert set(merged_track.tags) == expected_tags
# Verify merged source data
assert "lastfm" in merged_track.source_data
assert "spotify" in merged_track.source_data
assert merged_track.source == MetadataSource.UNIFIED
def test_merge_different_tracks_raises_error(self):
"""Confirms that attempting to merge two different tracks raises a ValueError."""
# Create two different tracks
track1 = UnifiedTrackMetadata(
name="Paranoid Android",
artist="Radiohead"
)
track2 = UnifiedTrackMetadata(
name="Creep",
artist="Radiohead"
)
# Attempt to merge should raise ValueError
with pytest.raises(ValueError, match="Cannot merge different tracks"):
track1.merge_with(track2)
def test_calculate_underground_score(self):
"""Checks the logic for calculating a track's underground score based on its popularity metrics."""
# Test high underground score (low popularity)
underground_track = UnifiedTrackMetadata(
name="Obscure Track",
artist="Unknown Artist",
listeners=500, # Very low listeners
popularity=10, # Very low Spotify popularity
tags=["experimental", "underground", "noise"] # Underground tags
)
score = underground_track.calculate_underground_score()
# Should be high underground score (close to 1.0)
assert score > 0.7
assert underground_track.underground_score == score
# Test low underground score (high popularity)
mainstream_track = UnifiedTrackMetadata(
name="Popular Song",
artist="Famous Artist",
listeners=5000000, # High listeners
popularity=95, # High Spotify popularity
tags=["pop", "mainstream", "radio"] # Mainstream tags
)
score = mainstream_track.calculate_underground_score()
# Should be low underground score (close to 0.0)
assert score < 0.3
assert mainstream_track.underground_score == score
# Test medium underground score
medium_track = UnifiedTrackMetadata(
name="Indie Track",
artist="Indie Artist",
listeners=50000, # Medium listeners
popularity=50, # Medium Spotify popularity
tags=["indie", "alternative"] # Some underground elements
)
score = medium_track.calculate_underground_score()
# Should be medium underground score
assert 0.3 <= score <= 0.7
assert medium_track.underground_score == score
def test_calculate_underground_score_no_data(self):
"""Test underground score calculation with no popularity data."""
track = UnifiedTrackMetadata(
name="Unknown Track",
artist="Unknown Artist"
# No listeners, popularity, or tags
)
score = track.calculate_underground_score()
# Should default to 0.5 when no data available
assert score == 0.5
assert track.underground_score == score
def test_track_matching_logic(self):
"""Test the _matches_track method for track comparison."""
track1 = UnifiedTrackMetadata(
name="Paranoid Android",
artist="Radiohead"
)
# Same track, different case
track2 = UnifiedTrackMetadata(
name="paranoid android",
artist="RADIOHEAD"
)
# Different track
track3 = UnifiedTrackMetadata(
name="Creep",
artist="Radiohead"
)
assert track1._matches_track(track2) is True
assert track1._matches_track(track3) is False
def test_post_init_normalization(self):
"""Test that __post_init__ properly normalizes and initializes fields."""
track = UnifiedTrackMetadata(
name=" Paranoid Android ", # Extra whitespace
artist=" Radiohead ", # Extra whitespace
tags=None, # Should be initialized to empty list
genres=None, # Should be initialized to empty list
similar_tracks=None, # Should be initialized to empty list
external_urls=None, # Should be initialized to empty dict
source_data=None # Should be initialized to empty dict
)
# Verify normalization
assert track.name == "Paranoid Android"
assert track.artist == "Radiohead"
# Verify initialization of collections
assert track.tags == []
assert track.genres == []
assert track.similar_tracks == []
assert track.external_urls == {}
assert track.source_data == {}
class TestMergeTrackMetadata:
"""Test the merge_track_metadata utility function."""
def test_merge_track_metadata_function(self):
"""Test the standalone merge_track_metadata function."""
# Create tracks with same name/artist but different data
track1 = UnifiedTrackMetadata(
name="Test Track",
artist="Test Artist",
listeners=1000,
tags=["rock"]
)
track2 = UnifiedTrackMetadata(
name="Test Track",
artist="Test Artist",
popularity=75,
tags=["alternative"]
)
track3 = UnifiedTrackMetadata(
name="Different Track",
artist="Test Artist",
popularity=50
)
tracks = [track1, track2, track3]
merged_tracks = merge_track_metadata(tracks)
# Should have 2 tracks (track1 and track2 merged, track3 separate)
assert len(merged_tracks) == 2
# Find the merged track
merged_track = next(t for t in merged_tracks if t.name == "Test Track")
different_track = next(t for t in merged_tracks if t.name == "Different Track")
# Verify merged data
assert merged_track.listeners == 1000 # From track1
assert merged_track.popularity == 75 # From track2
assert set(merged_track.tags) == {"rock", "alternative"} # Merged tags
assert merged_track.source == MetadataSource.UNIFIED
# Verify separate track unchanged
assert different_track.popularity == 50
assert different_track.name == "Different Track"