Pure value type bundling playlists and callbacks needed to build a track context menu; both tests pass (TDD).feat/music-streaming
parent
793fe036ad
commit
c9cdf80a14
@ -0,0 +1,10 @@ |
||||
import Foundation |
||||
|
||||
struct TrackContextMenuConfig { |
||||
let playlists: [Playlist] |
||||
let lastUsedPlaylistName: String? |
||||
let selectedPlaylist: Playlist? |
||||
let onAddToPlaylist: (Track, Playlist) -> Void |
||||
let onAddToLastPlaylist: ((Track) -> Void)? |
||||
let onRemoveFromPlaylist: ((Track) -> Void)? |
||||
} |
||||
@ -0,0 +1,72 @@ |
||||
import Testing |
||||
@testable import Music |
||||
|
||||
struct TrackContextMenuConfigTests { |
||||
// Builds a config with all fields set and verifies: |
||||
// - stored playlists, lastUsedPlaylistName, selectedPlaylist match the inputs |
||||
// - onAddToPlaylist callback fires with the correct track and playlist |
||||
// - onAddToLastPlaylist callback fires with the correct track |
||||
// - onRemoveFromPlaylist callback fires with the correct track |
||||
// - when optional callbacks are nil, optionally calling them is safe |
||||
|
||||
@Test func storesPropertiesAndFiresCallbacks() { |
||||
// 1. Create fixture data |
||||
let pl1 = Playlist.fixture(id: 1, name: "Favorites") |
||||
let pl2 = Playlist.fixture(id: 2, name: "Chill") |
||||
let track = Track.fixture(id: 42, title: "Test") |
||||
|
||||
var addedTrack: Track? = nil |
||||
var addedPlaylist: Playlist? = nil |
||||
var lastTrack: Track? = nil |
||||
var removedTrack: Track? = nil |
||||
|
||||
// 2. Build config with all callbacks |
||||
let config = TrackContextMenuConfig( |
||||
playlists: [pl1, pl2], |
||||
lastUsedPlaylistName: "Favorites", |
||||
selectedPlaylist: pl1, |
||||
onAddToPlaylist: { t, p in addedTrack = t; addedPlaylist = p }, |
||||
onAddToLastPlaylist: { t in lastTrack = t }, |
||||
onRemoveFromPlaylist: { t in removedTrack = t } |
||||
) |
||||
|
||||
// 3. Verify stored properties |
||||
#expect(config.playlists.count == 2) |
||||
#expect(config.playlists[0].name == "Favorites") |
||||
#expect(config.lastUsedPlaylistName == "Favorites") |
||||
#expect(config.selectedPlaylist == pl1) |
||||
|
||||
// 4. Invoke callbacks and verify they fire correctly |
||||
config.onAddToPlaylist(track, pl2) |
||||
config.onAddToLastPlaylist?(track) |
||||
config.onRemoveFromPlaylist?(track) |
||||
|
||||
#expect(addedTrack?.id == track.id) |
||||
#expect(addedPlaylist?.id == pl2.id) |
||||
#expect(lastTrack?.id == track.id) |
||||
#expect(removedTrack?.id == track.id) |
||||
} |
||||
|
||||
@Test func nilOptionalCallbacksAreSafe() { |
||||
// Verifies that a config with nil optional callbacks does not crash |
||||
// when you call them via optional chaining (the normal usage pattern) |
||||
let pl = Playlist.fixture(id: 1, name: "Rock") |
||||
let track = Track.fixture() |
||||
|
||||
let config = TrackContextMenuConfig( |
||||
playlists: [pl], |
||||
lastUsedPlaylistName: nil, |
||||
selectedPlaylist: nil, |
||||
onAddToPlaylist: { _, _ in }, |
||||
onAddToLastPlaylist: nil, |
||||
onRemoveFromPlaylist: nil |
||||
) |
||||
|
||||
// These must not crash |
||||
config.onAddToLastPlaylist?(track) |
||||
config.onRemoveFromPlaylist?(track) |
||||
|
||||
#expect(config.lastUsedPlaylistName == nil) |
||||
#expect(config.selectedPlaylist == nil) |
||||
} |
||||
} |
||||
Loading…
Reference in new issue