"""Unit tests for playlist/queries/formatting.py""" import decimal from datetime import date, datetime, timezone from unittest.mock import Mock import pytest from playlist.queries.formatting import ( _clean_nested_arrays, _format_dict_of_placement_rows, _format_placement_row, aggregate_breakdown, format_placements, format_placements_with_gsr_split, format_placements_with_total_count, format_row, get_max_available_playlist_position_date, ) class TestCleanNestedArrays: """Tests for _clean_nested_arrays helper function.""" def test_clean_nested_arrays_removes_empty_objects(self): """Test that empty objects are removed from nested arrays.""" obj = { "streams_array": [{}], "listeners_array": [{}], "dimension_value": "US", } result = _clean_nested_arrays(obj) assert result == { "listeners_array": [], "streams_array": [], "dimension_value": "US", } def test_clean_nested_arrays_preserves_non_empty_objects(self): """Test that non-empty objects are preserved.""" obj = { "streams_array": [ {"activity_date": "2023-01-01", "streams": 100}, {"activity_date": "2023-01-02", "streams": 200}, ], "listeners_array": [ {"activity_date": "2023-01-01", "listeners": 50}, {"activity_date": "2023-01-02", "listeners": 75}, ], "dimension_value": "US", } result = _clean_nested_arrays(obj) assert len(result["streams_array"]) == 2 assert len(result["listeners_array"]) == 2 assert result["streams_array"][0]["streams"] == 100 assert result["listeners_array"][1]["listeners"] == 75 def test_clean_nested_arrays_deeply_nested(self): """Test cleaning deeply nested structures.""" obj = { "dimension_value": "US", "streams_array": [ { "activity_date": "2023-01-01", "streams": 100, "nested_data": [ {"value": "test"}, {}, # Empty object should be removed ], }, ], "listeners_array": [ { "activity_date": "2023-01-01", "listeners": 50, "nested_data": [{}], # Empty object should be removed }, ], } result = _clean_nested_arrays(obj) assert len(result["streams_array"][0]["nested_data"]) == 1 assert len(result["listeners_array"][0]["nested_data"]) == 1 assert result["streams_array"][0]["nested_data"][0]["value"] == "test" def test_clean_nested_arrays_with_non_dict_input(self): """Test that non-dict inputs are returned as-is.""" result = _clean_nested_arrays("not a dict") assert result == "not a dict" class TestFormatRow: """Tests for format_row function.""" def test_format_row_datetime_conversion(self): """Test that datetime objects are converted to ISO format with UTC timezone.""" dt = datetime(2023, 1, 15, 10, 30, 45) record = {"activity_date": dt, "name": "test"} result = format_row(record) assert result["activity_date"] == "2023-01-15T10:30:45+00:00" assert result["name"] == "test" def test_format_row_date_conversion(self): """Test that date objects are converted to ISO format.""" d = date(2023, 1, 15) record = {"start_date": d} result = format_row(record) assert result["start_date"] == "2023-01-15" def test_format_row_decimal_conversion(self): """Test that Decimal objects are converted to floats.""" dec_value = decimal.Decimal("123.456") record = {"price": dec_value} result = format_row(record) assert result["price"] == 123.456 assert isinstance(result["price"], float) def test_format_row_store_id_to_int(self): """Test that store_id is converted to integer.""" record = {"store_id": "286"} result = format_row(record) assert result["store_id"] == 286 assert isinstance(result["store_id"], int) def test_format_row_store_id_already_int(self): """Test that store_id already as int is preserved.""" record = {"store_id": 286} result = format_row(record) assert result["store_id"] == 286 def test_format_row_store_id_none(self): """Test that store_id as None is preserved.""" record = {"store_id": None} result = format_row(record) assert result["store_id"] is None def test_format_row_array_field_none_to_empty_list(self): """Test that None array fields become empty lists.""" record = {"streams_array": None} result = format_row(record, array_fields=["streams_array"]) assert result["streams_array"] == [] def test_format_row_array_field_python_list(self): """Test that Python list array fields are cleaned.""" record = { "streams_array": [ {"activity_date": "2023-01-01", "streams": 100}, {}, # Empty object should be removed ] } result = format_row(record, array_fields=["streams_array"]) assert len(result["streams_array"]) == 1 assert result["streams_array"][0]["streams"] == 100 def test_format_row_array_field_json_string(self): """Test that JSON string array fields are parsed and cleaned.""" record = {"dimensions": '[{"value": "US", "streams": 100}, {}]'} result = format_row(record, array_fields=["dimensions"]) assert len(result["dimensions"]) == 1 assert result["dimensions"][0]["value"] == "US" def test_format_row_array_field_nested_cleaning(self): """Test that nested empty objects are cleaned.""" record = { "dimensions": [ { "dimension_value": "US", "streams_array": [{}], # Empty nested array } ], } result = format_row(record, array_fields=["dimensions"]) assert result["dimensions"][0]["streams_array"] == [] def test_format_row_array_field_invalid_json(self): """Test that invalid JSON defaults to empty list.""" record = {"streams_array": "invalid json"} result = format_row(record, array_fields=["streams_array"]) assert result["streams_array"] == [] def test_format_row_multiple_field_types(self): """Test format_row with multiple field types.""" dt = datetime(2023, 1, 15) record = { "activity_date": dt, "store_id": "286", "price": decimal.Decimal("99.99"), "streams_array": [{"value": 100}], "name": "test", } result = format_row(record, array_fields=["streams_array"]) assert result["activity_date"] == "2023-01-15T00:00:00+00:00" assert result["store_id"] == 286 assert result["price"] == 99.99 assert result["streams_array"] == [{"value": 100}] assert result["name"] == "test" class TestFormatPlacementRow: """Tests for _format_placement_row function.""" def test_format_placement_row_basic(self): """Test basic placement row formatting.""" record = { "store_id": "286", "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, } result = _format_placement_row(record) assert result["store_id"] == 286 assert result["store_playlist_id"] == "spotify:playlist:123" assert result["streams_array"] == [] assert result["dimensions"] == [] assert result["brand_ids_array"] == [] assert result["playlist_genres"] == [] def test_format_placement_row_with_data(self): """Test placement row formatting with actual data.""" record = { "store_id": 1, "store_playlist_id": "apple:playlist:456", "isrc": "USRC17607839", "streams_array": [ {"activity_date": "2023-01-01", "streams": 100}, {"activity_date": "2023-01-02", "streams": 200}, ], "brand_ids_array": ["uuid1", "uuid2"], "dimensions": None, "playlist_genres": None, } result = _format_placement_row(record) assert result["store_id"] == 1 assert len(result["streams_array"]) == 2 assert result["brand_ids_array"] == ["uuid1", "uuid2"] class TestFormatDictOfPlacementRows: """Tests for _format_dict_of_placement_rows function.""" def test_format_dict_of_placement_rows(self): """Test formatting a dictionary of placement rows.""" row1 = { "store_id": "286", "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, } row2 = { "store_id": "1", "store_playlist_id": "apple:playlist:456", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, } test_dict = {"key1": row1, "key2": row2} result = _format_dict_of_placement_rows(test_dict) assert "key1" in result assert "key2" in result assert result["key1"]["store_id"] == 286 assert result["key2"]["store_id"] == 1 class TestFormatPlacements: """Tests for format_placements function.""" def test_format_placements_empty_list(self): """Test formatting empty placements list.""" result = format_placements([]) assert result == [] def test_format_placements_multiple_records(self): """Test formatting multiple placement records.""" row1 = { "store_id": "286", "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, } row2 = { "store_id": "1", "store_playlist_id": "apple:playlist:456", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, } result = format_placements([row1, row2]) assert len(result) == 2 assert result[0]["store_id"] == 286 assert result[1]["store_id"] == 1 class TestFormatPlacementsWithTotalCount: """Tests for format_placements_with_total_count function.""" def test_format_placements_with_total_count_basic(self): """Test formatting placements with total count.""" row = { "store_id": "286", "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "total_count": 5, "store_name": "Spotify", } result, total_count = format_placements_with_total_count([row]) assert len(result) == 1 assert total_count == 5 assert result[0]["store_id"] == 286 assert "total_count" not in result[0] def test_format_placements_with_total_count_multiple(self): """Test with multiple records - total_count from last one.""" row1 = { "store_id": "286", "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "total_count": 3, "store_name": "Spotify", } row2 = { "store_id": "1", "store_playlist_id": "apple:playlist:456", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "total_count": 7, "store_name": "Apple Music", } result, total_count = format_placements_with_total_count([row1, row2]) assert len(result) == 2 assert total_count == 7 # Last total_count assert result[0]["store_name"] == "Spotify" assert result[1]["store_name"] == "Apple Music" def test_format_placements_with_total_count_no_total(self): """Test when total_count is missing.""" row = { "store_id": "286", "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "store_name": "Spotify", } result, total_count = format_placements_with_total_count([row]) assert total_count == 0 class TestFormatPlacementsWithGSRSplit: """Tests for format_placements_with_gsr_split function.""" def test_format_placements_with_gsr_split_has_gsr(self): """Test placement with real GSR.""" row = { "store_id": 286, # Already int "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "gsr_id": "gsr:123", "chartmetric_track_name": "Track Name", "chartmetric_artist_name": "Artist Name", "chartmetric_artwork_url": "http://example.com/art.jpg", "total_count": 5, "store_name": "Spotify", } with_gsr, placeholders, total_count = format_placements_with_gsr_split([row]) assert len(with_gsr) == 1 assert len(placeholders) == 0 assert total_count == 5 assert "gsr_id" not in with_gsr[0] # Should be popped assert "chartmetric_track_name" not in with_gsr[0] def test_format_placements_with_gsr_split_no_gsr(self): """Test placement without GSR (placeholder).""" row = { "store_id": 286, "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "gsr_id": None, "chartmetric_track_name": "Track Name", "chartmetric_artist_name": "Artist Name", "chartmetric_artwork_url": "http://example.com/art.jpg", "total_count": 5, "store_name": "Spotify", } with_gsr, placeholders, total_count = format_placements_with_gsr_split([row]) assert len(with_gsr) == 0 assert len(placeholders) == 1 assert total_count == 5 assert placeholders[0]["track_name"] == "Track Name" assert placeholders[0]["artist_name"] == "Artist Name" assert placeholders[0]["artwork_url"] == "http://example.com/art.jpg" def test_format_placements_with_gsr_split_mixed(self): """Test with both GSR and non-GSR placements.""" row1 = { "store_id": 286, "store_playlist_id": "spotify:playlist:123", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "gsr_id": "gsr:123", "chartmetric_track_name": "Track 1", "chartmetric_artist_name": "Artist 1", "chartmetric_artwork_url": "http://example.com/art1.jpg", "total_count": 5, "store_name": "Spotify", } row2 = { "store_id": 1, "store_playlist_id": "apple:playlist:456", "streams_array": None, "dimensions": None, "brand_ids_array": None, "playlist_genres": None, "gsr_id": None, "chartmetric_track_name": "Track 2", "chartmetric_artist_name": "Artist 2", "chartmetric_artwork_url": "http://example.com/art2.jpg", "total_count": 5, "store_name": "Apple Music", } with_gsr, placeholders, total_count = format_placements_with_gsr_split( [row1, row2] ) assert len(with_gsr) == 1 assert len(placeholders) == 1 assert with_gsr[0]["store_name"] == "Spotify" assert placeholders[0]["store_name"] == "Apple Music" class TestAggregateBreakdown: """Tests for aggregate_breakdown function.""" def test_aggregate_breakdown_empty_records(self): """Test aggregate_breakdown with empty records.""" result = aggregate_breakdown([]) assert result["stores"] == {} assert result["types"] == {} assert result["total_count"] == 0 class TestGetMaxAvailablePlaylistPositionDate: """Tests for get_max_available_playlist_position_date function.""" def test_get_max_available_playlist_position_date_format(self): """Test that returned date is in ISO format.""" result = get_max_available_playlist_position_date() assert isinstance(result, str) # Verify it's a valid ISO format date (YYYY-MM-DD) assert len(result) == 10 assert result[4] == "-" assert result[7] == "-"