broken changes

This commit is contained in:
Mark Gregory
2026-11-05 17:21:18 +00:00
parent 8cffb40f17
commit 83a97ff3fd
5 changed files with 72 additions and 39 deletions
+47 -8
View File
@@ -1352,7 +1352,10 @@ final class KJamsCloneTests: XCTestCase {
try await Task.sleep(nanoseconds:200_000_000);host.layoutSubtreeIfNeeded();host.displayIfNeeded()
if let image = host.bitmapImageRepForCachingDisplay(in:host.bounds) { host.cacheDisplay(in:host.bounds,to:image) }
func click(_ x: Double,_ top: Double) async throws {
let point = NSPoint(x:x,y:900-top-44)
func descendants(_ view: NSView) -> [NSView] { [view]+view.subviews.flatMap{descendants($0)} }
let tabs = try XCTUnwrap(descendants(host).compactMap{$0 as? NSTabView}.first)
let rect = tabs.contentRect
let point = tabs.convert(NSPoint(x:rect.minX+x,y:tabs.isFlipped ? rect.minY+top : rect.maxY-top),to:nil)
for type in [NSEvent.EventType.leftMouseDown,.leftMouseUp] {
let event = try XCTUnwrap(NSEvent.mouseEvent(with:type,location:point,modifierFlags:[],timestamp:ProcessInfo.processInfo.systemUptime,windowNumber:window.windowNumber,context:nil,eventNumber:0,clickCount:1,pressure:type == .leftMouseDown ? 1 : 0))
NSApp.sendEvent(event)
@@ -1497,8 +1500,12 @@ final class KJamsCloneTests: XCTestCase {
host.layoutSubtreeIfNeeded();if let rep = host.bitmapImageRepForCachingDisplay(in:host.bounds) { host.cacheDisplay(in:host.bounds,to:rep);try rep.representation(using:.png,properties:[:])!.write(to:URL(fileURLWithPath:"/tmp/kjmix-rotation-test-"+name+".png")) }
}
func click(_ x: Double,_ top: Double) async throws {
func descendants(_ view: NSView) -> [NSView] { [view]+view.subviews.flatMap{descendants($0)} }
let tabs = try XCTUnwrap(descendants(host).compactMap{$0 as? NSTabView}.first)
let rect = tabs.contentRect
let point = tabs.convert(NSPoint(x:rect.minX+x,y:tabs.isFlipped ? rect.minY+top : rect.maxY-top),to:nil)
for type in [NSEvent.EventType.leftMouseDown,.leftMouseUp] {
let event = try XCTUnwrap(NSEvent.mouseEvent(with:type,location:NSPoint(x:x,y:760-top-44),modifierFlags:[],timestamp:ProcessInfo.processInfo.systemUptime,windowNumber:window.windowNumber,context:nil,eventNumber:0,clickCount:1,pressure:type == .leftMouseDown ? 1 : 0));NSApp.sendEvent(event)
let event = try XCTUnwrap(NSEvent.mouseEvent(with:type,location:point,modifierFlags:[],timestamp:ProcessInfo.processInfo.systemUptime,windowNumber:window.windowNumber,context:nil,eventNumber:0,clickCount:1,pressure:type == .leftMouseDown ? 1 : 0));NSApp.sendEvent(event)
}
try await Task.sleep(nanoseconds:120_000_000)
}
@@ -2104,6 +2111,9 @@ extension KJamsCloneTests {
XCTAssertEqual(device.stereoPairs,[0,2])
let preset = DJAudioRouting.controllerPreset(device,mode:"Internal")
XCTAssertEqual(preset.main.firstChannel,0);XCTAssertEqual(preset.cue.firstChannel,2)
let switched = preset.changingMode("External",preferred:device)
XCTAssertTrue(switched.cue.uid.isEmpty,"Switching to external clears cue if both pairs are used by public decks")
XCTAssertNoThrow(try switched.validate(devices:[device],defaultID:1))
let external = DJAudioRouting.controllerPreset(device,mode:"External")
XCTAssertEqual(external.deckA.firstChannel,0);XCTAssertEqual(external.deckB.firstChannel,2)
XCTAssertNoThrow(try external.validate(devices:[device],defaultID:1))
@@ -2114,6 +2124,22 @@ extension KJamsCloneTests {
XCTAssertNoThrow(try routing.validate(devices:[device],defaultID:1))
routing.deckB.firstChannel = 0;XCTAssertThrowsError(try routing.validate(devices:[device],defaultID:1))
}
@MainActor func testNativeChannelPickerListsBothPairsAndChangesBindingImmediately() async throws {
var selected = 0
let host = NSHostingView(rootView:DJAudioChannelPicker(value:Binding(get:{selected},set:{selected = $0}),pairs:[0,2],label:"Test channels").frame(width:140,height:30))
host.frame = NSRect(x:0,y:0,width:140,height:30)
let window = NSWindow(contentRect:host.frame,styleMask:[.borderless],backing:.buffered,defer:false)
window.contentView = host;window.setFrameOrigin(NSPoint(x:-10000,y:-10000));window.orderFront(nil)
defer { window.orderOut(nil);window.contentView = nil }
try await Task.sleep(nanoseconds:100_000_000);host.layoutSubtreeIfNeeded()
func descendants(_ view: NSView) -> [NSView] { [view]+view.subviews.flatMap{descendants($0)} }
let control = try XCTUnwrap(descendants(host).compactMap{$0 as? NSPopUpButton}.first)
XCTAssertEqual(control.itemTitles,["ch 1–2","ch 3–4"])
control.selectItem(withTag:2);_ = control.sendAction(try XCTUnwrap(control.action),to:control.target)
XCTAssertEqual(selected,2)
control.selectItem(withTag:0);_ = control.sendAction(try XCTUnwrap(control.action),to:control.target)
XCTAssertEqual(selected,0)
}
@MainActor func testAudioOutputsAndActualFourChannelRoutingWhenInterfaceAttached() async throws {
let outputs = DJAudioDevice.outputs()
print("DJ audio discovery:",outputs.map { "\($0.name) [\($0.outputChannels) out / \($0.inputChannels) in]" }.joined(separator:", "))
@@ -2140,6 +2166,19 @@ extension KJamsCloneTests {
let menus = descendants(host).compactMap{$0 as? NSPopUpButton}
for menu in menus { menu.menu?.update() }
XCTAssertTrue(menus.contains{$0.itemTitles.contains("ch 1–2") && $0.itemTitles.contains("ch 3–4")},"Native channel menus expose both pairs from the attached Numark")
let main = try XCTUnwrap(menus.first{$0.identifier?.rawValue == "Main Output channels"})
let cue = try XCTUnwrap(menus.first{$0.identifier?.rawValue == "Pre-Cueing channels"})
func choose(_ button: NSPopUpButton,_ pair: Int) async throws {
button.selectItem(withTag:pair);_ = button.sendAction(try XCTUnwrap(button.action),to:button.target)
try await Task.sleep(nanoseconds:100_000_000)
}
try await choose(main,2)
XCTAssertEqual(model.dj.routing.main.firstChannel,0,"Conflicting draft keeps the last valid live route")
try await choose(cue,0)
XCTAssertEqual(model.dj.routing.main.firstChannel,2);XCTAssertEqual(model.dj.routing.cue.firstChannel,0)
XCTAssertEqual(model.dj.a.player.outputChannelMap(),[-1,-1,0,1],"Native selection applies immediately to the actual output unit")
try await choose(main,0);try await choose(cue,2)
XCTAssertEqual(model.dj.routing.main.firstChannel,0);XCTAssertEqual(model.dj.routing.cue.firstChannel,2)
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/audio-routing.png")) }
}
func testXMLStandardLEDOutputHonoursOverridesAndInversion() throws {
@@ -2270,14 +2309,14 @@ extension KJamsCloneTests {
defer { window.orderOut(nil);window.contentView = nil }
try await Task.sleep(nanoseconds:200_000_000);host.layoutSubtreeIfNeeded()
func descendants(_ view: NSView) -> [NSView] { [view]+view.subviews.flatMap{descendants($0)} }
let tabs = try XCTUnwrap(descendants(host).compactMap{$0 as? NSSegmentedControl}.first{$0.segmentCount == 2})
let tabs = try XCTUnwrap(descendants(host).compactMap{$0 as? NSTabView}.first{$0.numberOfTabViewItems == 2})
func selectTab(_ index: Int) async throws {
let point = tabs.convert(NSPoint(x:tabs.bounds.width*(index == 0 ? 0.25 : 0.75),y:tabs.bounds.midY),to:nil)
for type in [NSEvent.EventType.leftMouseDown,.leftMouseUp] {
let event = try XCTUnwrap(NSEvent.mouseEvent(with:type,location:point,modifierFlags:[],timestamp:ProcessInfo.processInfo.systemUptime,windowNumber:window.windowNumber,context:nil,eventNumber:0,clickCount:1,pressure:type == .leftMouseDown ? 1 : 0));NSApp.sendEvent(event)
}
tabs.selectTabViewItem(at:index)
try await Task.sleep(nanoseconds:100_000_000);host.layoutSubtreeIfNeeded()
XCTAssertEqual(tabs.selectedSegment,index)
XCTAssertEqual(tabs.selectedTabViewItem,tabs.tabViewItem(at:index))
if let inactive = tabs.tabViewItem(at:1-index).view {
XCTAssertTrue(inactive.superview == nil || inactive.isHiddenOrHasHiddenAncestor,"Inactive pages cannot intercept deck drops")
}
XCTAssertTrue(model.player.playing);XCTAssertTrue(model.dj.a.player.playing)
XCTAssertEqual(model.player.currentSongID,id);XCTAssertEqual(model.dj.a.player.currentSongID,id)
}