broken changes

This commit is contained in:
Mark Gregory
2026-11-05 16:54:59 +00:00
parent 13a6a9e1c8
commit 80a895febb
7 changed files with 379 additions and 43 deletions
+81
View File
@@ -2150,6 +2150,12 @@ extension KJamsCloneTests {
let initial = received.count
try await Task.sleep(nanoseconds:2_100_000_000)
XCTAssertGreaterThan(received.count,initial,"LED state is resent after the startup light show ends")
midi.applyXML(profile);midi.shutdown()
try await Task.sleep(nanoseconds:100_000_000)
XCTAssertTrue((0..<max(0,received.count-2)).contains{Array(received[$0..<($0+3)]) == [0x9E,0x7F,0]})
let stopped = received.count
try await Task.sleep(nanoseconds:2_100_000_000)
XCTAssertEqual(received.count,stopped,"Shutdown cancels delayed initialization and leaves LEDs reset")
}
func testDjayXMLLoadsAllSuppliedProfilesAndReportsUnsupportedActions() throws {
XCTAssertEqual(DJXMLProfile.bundled.count,210)
@@ -2249,3 +2255,78 @@ extension KJamsCloneTests {
if let rep = host.bitmapImageRepForCachingDisplay(in:host.bounds) { host.cacheDisplay(in:host.bounds,to:rep);try XCTUnwrap(rep.representation(using:.png,properties:[:])).write(to:URL(fileURLWithPath:"/private/tmp/kjmix-xml-mappings/karaoke-tab.png")) }
}
}
extension KJamsCloneTests {
@MainActor private func automixFixture(_ root: URL) throws -> (DJSystem,[Song]) {
let system = DJSystem(storageURL:root),library = try XCTUnwrap(system.library)
let fixture = try XCTUnwrap(Bundle(for:Self.self).resourceURL?.appendingPathComponent("Fixtures/Demo.mp3"))
for name in ["First","Second","Third"] {
let copy = root.appendingPathComponent(name+".mp3");try FileManager.default.copyItem(at:fixture,to:copy)
try library.add(title:name,audio:copy.path,cdg:nil)
}
try system.refresh();return (system,system.songs)
}
@MainActor func testChangingLoopSizeResizesActiveAudioRegionImmediately() throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
let (system,songs) = try automixFixture(root);system.load(songs[0],into:"A")
let deck = system.a,player = deck.player;defer { player.stop() }
deck.bpm = 240;deck.bpmConfirmed = true;deck.loopBeats = 4
player.defineLoop(start:0.25,end:1.25);player.seek(0.5);player.toggle()
deck.loopBeats = 8
XCTAssertEqual(player.loopOut!,2.25,accuracy:0.001);XCTAssertTrue(player.playing);XCTAssertTrue(player.loopEnabled)
deck.loopBeats = 2;XCTAssertEqual(player.loopOut!,0.75,accuracy:0.001)
XCTAssertEqual(player.loopIn!,0.25,accuracy:0.001);XCTAssertTrue(player.playing)
deck.loopBeats = 32;XCTAssertEqual(player.loopOut!,player.duration,accuracy:0.001)
}
@MainActor func testDJQueueOrderDuplicatesAndSettingsPersistWithoutAutoplay() throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
let (system,songs) = try automixFixture(root),queue = system.automix
queue.enqueue([songs[0],songs[1],songs[0]]);queue.seconds = 5;queue.matchTempo = true
let second = queue.entries[1].id;queue.move(second,by:-1)
XCTAssertEqual(queue.entries.map(\.song),[songs[1].id,songs[0].id,songs[0].id])
queue.remove(queue.entries.last!.id)
let restored = DJSystem(storageURL:root),saved = restored.automix
XCTAssertEqual(saved.entries.map(\.song),[songs[1].id,songs[0].id]);XCTAssertEqual(saved.seconds,5);XCTAssertTrue(saved.matchTempo)
XCTAssertFalse(saved.enabled);XCTAssertFalse(restored.a.player.playing);XCTAssertFalse(restored.b.player.playing)
}
@MainActor func testAutomixCrossfadesBothDecksAndYieldsToManualControl() throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
let (system,songs) = try automixFixture(root),queue = system.automix
defer { queue.stop();system.a.player.stop();system.b.player.stop() }
system.settings.autoPlayOnLoad = true;queue.enqueue(songs);queue.seconds = 0.2;queue.start(runTimer:false)
XCTAssertTrue(queue.enabled);XCTAssertTrue(system.a.player.playing);XCTAssertFalse(system.b.player.playing,"Preloaded track stays paused despite autoplay preference")
queue.mixNow(now:10);XCTAssertTrue(system.b.player.playing)
queue.tick(now:10.1);XCTAssertEqual(system.crossfader,0.5,accuracy:0.01)
queue.tick(now:10.3);XCTAssertEqual(queue.activeDeck,"B");XCTAssertEqual(system.crossfader,1)
XCTAssertFalse(system.a.player.playing);XCTAssertTrue(system.b.player.playing);XCTAssertEqual(queue.entries.count,1)
XCTAssertEqual(system.a.player.currentSongID,songs[2].id,"Next track is preloaded into the now silent deck")
system.crossfader = 0.5;queue.tick(now:11);XCTAssertFalse(queue.enabled);XCTAssertTrue(system.b.player.playing)
}
@MainActor func testAutomixTimerTransitionsAtTrackEndAndHonoursPause() async throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
let (system,songs) = try automixFixture(root),queue = system.automix
defer { queue.stop();system.a.player.stop();system.b.player.stop() }
queue.seconds = 0.1;queue.enqueue(Array(songs.prefix(2)));queue.start()
system.a.player.seek(system.a.player.duration-0.15)
try await Task.sleep(nanoseconds:500_000_000)
XCTAssertEqual(queue.activeDeck,"B");XCTAssertTrue(system.b.player.playing);XCTAssertFalse(system.a.player.playing)
system.b.player.toggle();try await Task.sleep(nanoseconds:120_000_000)
XCTAssertFalse(queue.enabled,"Manual pause hands control back to the operator")
}
@MainActor func testAutomixWaitsForLoopsAndSkipsUnavailableQueueEntries() throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
let (system,songs) = try automixFixture(root),queue = system.automix
defer { queue.stop();system.a.player.stop();system.b.player.stop() }
let missing = try XCTUnwrap(system.library).add(title:"Missing",audio:root.appendingPathComponent("missing.mp3").path,cdg:nil)
try system.refresh();queue.enqueue([try XCTUnwrap(system.songs.first{$0.id == missing}),songs[0],songs[1]])
queue.start(runTimer:false);XCTAssertEqual(system.a.player.currentSongID,songs[0].id)
system.a.player.defineLoop(start:0,end:0.5);queue.tick(now:10)
XCTAssertNil(queue.progress);XCTAssertTrue(queue.enabled);XCTAssertTrue(queue.message.contains("Loop active"))
queue.stop();XCTAssertTrue(system.a.player.playing,"Stopping automation preserves current playback")
}
}