| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- import XCTest
- @testable import MixBoard
- final class GroupTemplateResolverTests: XCTestCase {
- private func makeTrack(
- artist: String = "Test Artist",
- album: String = "Test Album",
- genre: String = "Electronic",
- filePath: String = "Music/subfolder/song.mp3",
- fileFormat: String = "MP3",
- bpm: Double? = 128.0,
- musicalKey: String? = "Am",
- year: Int? = 2023
- ) -> Track {
- let track = Track(title: "Test Song", artist: artist, album: album, genre: genre, filePath: filePath, fileFormat: fileFormat)
- track.bpm = bpm
- track.musicalKey = musicalKey
- track.year = year
- return track
- }
- // MARK: - Basic Placeholder Resolution
- func testResolveArtistTemplate() {
- let track = makeTrack(artist: "Raekwon")
- let result = GroupTemplateResolver.resolve(template: "{Artist}", for: track)
- XCTAssertEqual(result, "Raekwon")
- }
- func testResolveAlbumTemplate() {
- let track = makeTrack(album: "Only Built 4 Cuban Linx")
- let result = GroupTemplateResolver.resolve(template: "{Album}", for: track)
- XCTAssertEqual(result, "Only Built 4 Cuban Linx")
- }
- func testResolveGenreTemplate() {
- let track = makeTrack(genre: "Hip-Hop")
- let result = GroupTemplateResolver.resolve(template: "{Genre}", for: track)
- XCTAssertEqual(result, "Hip-Hop")
- }
- func testResolveDateTemplate() {
- let track = makeTrack(year: 1995)
- let result = GroupTemplateResolver.resolve(template: "{Date}", for: track)
- XCTAssertEqual(result, "1995")
- }
- func testResolveFormatTemplate() {
- let track = makeTrack(fileFormat: "FLAC")
- let result = GroupTemplateResolver.resolve(template: "{Format}", for: track)
- XCTAssertEqual(result, "FLAC")
- }
- func testResolveKeyTemplate() {
- let track = makeTrack(musicalKey: "Cm")
- let result = GroupTemplateResolver.resolve(template: "{Key}", for: track)
- XCTAssertEqual(result, "Cm")
- }
- // MARK: - Folder Resolution
- func testResolveFolderTemplate() {
- let track = makeTrack(filePath: "Music/Hip-Hop/Raekwon/track.mp3")
- let result = GroupTemplateResolver.resolve(template: "{Folder}", for: track)
- XCTAssertEqual(result, "Raekwon")
- }
- func testResolveFolderRootPath() {
- let track = makeTrack(filePath: "song.mp3")
- let result = GroupTemplateResolver.resolve(template: "{Folder}", for: track)
- XCTAssertEqual(result, "Root")
- }
- // MARK: - BPM Range
- func testResolveBPMRange() {
- let track = makeTrack(bpm: 125.0)
- let result = GroupTemplateResolver.resolve(template: "{BPM}", for: track)
- XCTAssertEqual(result, "120-130 BPM")
- }
- func testResolveBPMRangeExact() {
- let track = makeTrack(bpm: 130.0)
- let result = GroupTemplateResolver.resolve(template: "{BPM}", for: track)
- XCTAssertEqual(result, "130-140 BPM")
- }
- func testResolveBPMNil() {
- let track = makeTrack(bpm: nil)
- let result = GroupTemplateResolver.resolve(template: "{BPM}", for: track)
- XCTAssertEqual(result, "No BPM")
- }
- // MARK: - Compound Templates
- func testResolveAlbumDateTemplate() {
- let track = makeTrack(album: "Madvillainy", year: 2004)
- let result = GroupTemplateResolver.resolve(template: "{Album} ({Date})", for: track)
- XCTAssertEqual(result, "Madvillainy (2004)")
- }
- func testResolveArtistAlbumTemplate() {
- let track = makeTrack(artist: "MF DOOM", album: "Operation: Doomsday")
- let result = GroupTemplateResolver.resolve(template: "{Artist} — {Album}", for: track)
- XCTAssertEqual(result, "MF DOOM — Operation: Doomsday")
- }
- // MARK: - Missing/Empty Data Handling
- func testResolveEmptyTemplate() {
- let track = makeTrack()
- let result = GroupTemplateResolver.resolve(template: "", for: track)
- XCTAssertEqual(result, "")
- }
- func testResolveEmptyArtist() {
- let track = makeTrack(artist: "")
- let result = GroupTemplateResolver.resolve(template: "{Artist}", for: track)
- XCTAssertEqual(result, "Unknown Artist")
- }
- func testResolveEmptyAlbum() {
- let track = makeTrack(album: "")
- let result = GroupTemplateResolver.resolve(template: "{Album}", for: track)
- XCTAssertEqual(result, "Unknown Album")
- }
- func testResolveEmptyGenre() {
- let track = makeTrack(genre: "")
- let result = GroupTemplateResolver.resolve(template: "{Genre}", for: track)
- XCTAssertEqual(result, "Unknown Genre")
- }
- func testResolveEmptyFormat() {
- let track = makeTrack(fileFormat: "")
- let result = GroupTemplateResolver.resolve(template: "{Format}", for: track)
- XCTAssertEqual(result, "Unknown")
- }
- func testResolveNilKey() {
- let track = makeTrack(musicalKey: nil)
- let result = GroupTemplateResolver.resolve(template: "{Key}", for: track)
- XCTAssertEqual(result, "Unknown Key")
- }
- func testResolveNilDateCleansUpBrackets() {
- let track = makeTrack(album: "Some Album", year: nil)
- let result = GroupTemplateResolver.resolve(template: "{Album} ({Date})", for: track)
- // Empty parens should be cleaned up
- XCTAssertEqual(result, "Some Album")
- }
- func testResolveUnknownArtistCleanup() {
- let track = makeTrack(artist: "")
- let result = GroupTemplateResolver.resolve(template: "{Artist} — {Album}", for: track)
- // " — Unknown Artist" should be stripped — but since Artist is first, it stays
- // The cleanup rule is " — Unknown Artist" specifically
- XCTAssertFalse(result.isEmpty)
- }
- func testResolveAllEmptyFieldsReturnsUngrouped() {
- let track = Track(title: "Bare", filePath: "song.mp3")
- // With all empty, the resolved string may end up blank after cleanup
- let result = GroupTemplateResolver.resolve(template: "{Date}", for: track)
- // Year is nil → Date resolves to "" → template becomes "" → should return "Ungrouped"
- XCTAssertEqual(result, "Ungrouped")
- }
- // MARK: - Presets & Placeholders
- func testPresetsExist() {
- XCTAssertFalse(GroupTemplateResolver.presets.isEmpty)
- XCTAssertGreaterThanOrEqual(GroupTemplateResolver.presets.count, 8)
- }
- func testPresetsContainNoGrouping() {
- let noGrouping = GroupTemplateResolver.presets.first { $0.template.isEmpty }
- XCTAssertNotNil(noGrouping)
- XCTAssertEqual(noGrouping?.name, "No Grouping")
- }
- func testPlaceholdersExist() {
- XCTAssertEqual(GroupTemplateResolver.placeholders.count, 8)
- }
- func testAllPlaceholderTokensHaveBraces() {
- for placeholder in GroupTemplateResolver.placeholders {
- XCTAssertTrue(placeholder.token.hasPrefix("{"), "\(placeholder.token) should start with {")
- XCTAssertTrue(placeholder.token.hasSuffix("}"), "\(placeholder.token) should end with }")
- }
- }
- func testAllPlaceholderDescriptionsNonEmpty() {
- for placeholder in GroupTemplateResolver.placeholders {
- XCTAssertFalse(placeholder.description.isEmpty, "\(placeholder.token) should have a description")
- }
- }
- }
|