| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- import XCTest
- @testable import MixBoard
- /// Tests for FileNameTemplate.
- final class FileNameTemplateTests: XCTestCase {
- private func makeTrack(
- title: String = "Spot Rusherz",
- artist: String = "Raekwon",
- album: String = "Only Built 4 Cuban Linx",
- genre: String = "Hip-Hop",
- bpm: Double? = 95,
- key: String? = "Dm",
- format: String = "MP3",
- duration: TimeInterval = 193
- ) -> Track {
- let t = Track(title: title, artist: artist, album: album, genre: genre, filePath: "/fake.\(format.lowercased())", duration: duration, fileFormat: format)
- t.bpm = bpm
- t.musicalKey = key
- return t
- }
- // MARK: - Basic Templates
- func testDefaultTemplate() {
- let track = makeTrack()
- let result = FileNameTemplate.generate(template: FileNameTemplate.defaultTemplate, track: track, playlistIndex: 0, totalTracks: 10)
- XCTAssertTrue(result.contains("Raekwon"))
- XCTAssertTrue(result.contains("Only Built 4 Cuban Linx"))
- XCTAssertTrue(result.contains("Spot Rusherz"))
- }
- func testTrackNumberPadding() {
- let track = makeTrack()
- let r1 = FileNameTemplate.generate(template: "{track} {title}", track: track, playlistIndex: 0, totalTracks: 10)
- XCTAssertTrue(r1.hasPrefix("01"))
- let r2 = FileNameTemplate.generate(template: "{track} {title}", track: track, playlistIndex: 4, totalTracks: 150)
- XCTAssertTrue(r2.hasPrefix("005"))
- }
- func testAllVariables() {
- let track = makeTrack()
- let all = "{track} {artist} {album} {title} {genre} {bpm} {key} {duration} {format} {samplerate} {bitdepth}"
- let result = FileNameTemplate.generate(template: all, track: track, playlistIndex: 2, totalTracks: 10)
- XCTAssertTrue(result.contains("03"))
- XCTAssertTrue(result.contains("Raekwon"))
- XCTAssertTrue(result.contains("Only Built 4 Cuban Linx"))
- XCTAssertTrue(result.contains("Spot Rusherz"))
- XCTAssertTrue(result.contains("Hip-Hop"))
- XCTAssertTrue(result.contains("95"))
- XCTAssertTrue(result.contains("Dm"))
- XCTAssertTrue(result.contains("MP3"))
- // Duration colon gets sanitized to _ for filenames, so check for digits
- XCTAssertTrue(result.contains("3") && result.contains("13"), "Should contain duration digits")
- }
- func testEmptyFields() {
- let track = makeTrack(artist: "", album: "", bpm: nil, key: nil)
- let result = FileNameTemplate.generate(template: "{artist} - {album} - {title}", track: track, playlistIndex: 0, totalTracks: 1)
- // Should clean up double separators
- XCTAssertTrue(result.contains("Spot Rusherz"))
- XCTAssertFalse(result.contains(" - - "))
- }
- func testFilesystemSanitization() {
- let track = makeTrack(title: "What/Ever: The *Best?")
- let result = FileNameTemplate.generate(template: "{title}", track: track, playlistIndex: 0, totalTracks: 1)
- XCTAssertFalse(result.contains("/"))
- XCTAssertFalse(result.contains(":"))
- XCTAssertFalse(result.contains("*"))
- XCTAssertFalse(result.contains("?"))
- }
- func testPreview() {
- let preview = FileNameTemplate.preview(template: "{artist} - {title}")
- XCTAssertTrue(preview.contains("Raekwon"))
- XCTAssertTrue(preview.contains("Spot Rusherz"))
- }
- func testPresetsExist() {
- XCTAssertGreaterThanOrEqual(FileNameTemplate.presets.count, 4)
- for preset in FileNameTemplate.presets {
- XCTAssertFalse(preset.name.isEmpty)
- XCTAssertFalse(preset.template.isEmpty)
- // Each preset should generate a non-empty result
- let result = FileNameTemplate.preview(template: preset.template)
- XCTAssertGreaterThan(result.count, 0)
- }
- }
- func testAvailableVariables() {
- XCTAssertGreaterThanOrEqual(FileNameTemplate.availableVariables.count, 10)
- for v in FileNameTemplate.availableVariables {
- XCTAssertTrue(v.token.hasPrefix("{"))
- XCTAssertTrue(v.token.hasSuffix("}"))
- XCTAssertFalse(v.description.isEmpty)
- }
- }
- func testBPMOnlyWhenPresent() {
- let track = makeTrack(bpm: nil)
- let result = FileNameTemplate.generate(template: "{title} [{bpm}]", track: track, playlistIndex: 0, totalTracks: 1)
- // Empty BPM should result in clean output (brackets cleaned)
- XCTAssertFalse(result.contains("[]"))
- }
- }
- /// Tests for ExportOptions with fileNameTemplate.
- final class ExportOptionsTests: XCTestCase {
- func testDefaultOptionsHaveNoTemplate() {
- let opts = ExportOptions.default
- XCTAssertNil(opts.fileNameTemplate)
- }
- func testTemplateCanBeSet() {
- var opts = ExportOptions.default
- opts.fileNameTemplate = "{track} {artist} - {title}"
- XCTAssertEqual(opts.fileNameTemplate, "{track} {artist} - {title}")
- }
- }
- /// Tests for PlaylistViewModel status messages.
- final class StatusMessageTests: XCTestCase {
- @MainActor
- func testShowStatus() async {
- let vm = PlaylistViewModel()
- vm.showStatus("Test message", duration: 0.5)
- XCTAssertEqual(vm.statusMessage, "Test message")
- // Wait for auto-clear
- try? await Task.sleep(for: .seconds(0.7))
- XCTAssertNil(vm.statusMessage)
- }
- @MainActor
- func testStatusOverwrite() {
- let vm = PlaylistViewModel()
- vm.showStatus("First")
- XCTAssertEqual(vm.statusMessage, "First")
- vm.showStatus("Second")
- XCTAssertEqual(vm.statusMessage, "Second")
- }
- }
|