import Testing import CoreGraphics @testable import OnyxNotch // Bildschirmkoordinaten auf macOS haben ihren Ursprung unten links, y wächst nach // oben. Die Notch sitzt also bei y = frame.maxY − höhe, nicht bei y = 0. @Suite("Notch-Geometrie") struct NotchGeometryTests { /// Gemessen auf dem Zielgerät (MacBook Pro Mac17,9, M5 Pro) am 10.08.2026. /// Dient als Referenzfall — wenn dieser Test bricht, hat Apple die /// Notch-Metrik geändert und nicht wir. static let builtIn = ScreenMetrics( frame: CGRect(x: 0, y: 0, width: 1800, height: 1169), safeAreaTop: 38, auxiliaryTopLeft: CGRect(x: 0, y: 1131, width: 790, height: 38), auxiliaryTopRight: CGRect(x: 1010, y: 1131, width: 790, height: 38) ) /// Typischer externer Monitor, rechts neben dem eingebauten angeordnet. static let external = ScreenMetrics( frame: CGRect(x: 1800, y: 0, width: 2560, height: 1440), safeAreaTop: 0, auxiliaryTopLeft: nil, auxiliaryTopRight: nil ) static let virtualSize = CGSize(width: 220, height: 32) // MARK: - Erkennung @Test("Eingebautes Display: echte Notch aus den Hilfsflächen berechnet") func physicalNotchFromRealDevice() { let g = NotchGeometry.resolve(Self.builtIn, virtualSize: Self.virtualSize) #expect(g.kind == .physical) #expect(g.rect == CGRect(x: 790, y: 1131, width: 220, height: 38)) } @Test("Externes Display ohne Notch: virtueller Ersatz, oben mittig") func virtualNotchOnExternal() { let g = NotchGeometry.resolve(Self.external, virtualSize: Self.virtualSize) #expect(g.kind == .virtual) // Mittig: 1800 + (2560 − 220)/2 = 2970 #expect(g.rect == CGRect(x: 2970, y: 1408, width: 220, height: 32)) } @Test("safeAreaTop ohne Hilfsflächen gilt nicht als Notch") func safeAreaWithoutAuxIsVirtual() { // Kommt bei manchen Spiegelungs- und Fernanzeige-Konfigurationen vor: // ein Inset ist gesetzt, aber es gibt keine Notch, um die man herumlegen // könnte. Ein Panel an dieser Stelle säße im Nichts. let odd = ScreenMetrics( frame: CGRect(x: 0, y: 0, width: 1800, height: 1169), safeAreaTop: 38, auxiliaryTopLeft: nil, auxiliaryTopRight: nil ) #expect(NotchGeometry.resolve(odd, virtualSize: Self.virtualSize).kind == .virtual) } @Test("Notch-Mitte liegt auf der Bildschirmmitte") func notchIsCentred() { let g = NotchGeometry.resolve(Self.builtIn, virtualSize: Self.virtualSize) #expect(g.rect.midX == Self.builtIn.frame.midX) } // MARK: - Auslösefläche @Test("Auslösefläche ist breiter und tiefer als die Notch") func triggerIsLargerThanNotch() { let g = NotchGeometry.resolve(Self.builtIn, virtualSize: Self.virtualSize) let t = g.triggerRect #expect(t.width > g.rect.width) #expect(t.height > g.rect.height) #expect(t.midX == g.rect.midX) } @Test("Auslösefläche ragt nie über den oberen Bildschirmrand hinaus") func triggerStaysOnScreen() { let g = NotchGeometry.resolve(Self.builtIn, virtualSize: Self.virtualSize) #expect(g.triggerRect.maxY <= Self.builtIn.frame.maxY) #expect(g.triggerRect.minX >= Self.builtIn.frame.minX) #expect(g.triggerRect.maxX <= Self.builtIn.frame.maxX) } @Test("Auslösefläche eines schmalen Bildschirms bleibt innerhalb") func triggerClampsOnNarrowScreen() { let narrow = ScreenMetrics( frame: CGRect(x: 0, y: 0, width: 240, height: 400), safeAreaTop: 0, auxiliaryTopLeft: nil, auxiliaryTopRight: nil ) let g = NotchGeometry.resolve(narrow, virtualSize: Self.virtualSize) #expect(g.triggerRect.minX >= 0) #expect(g.triggerRect.maxX <= 240) } // MARK: - Panelfläche @Test("Panel hängt unter der Notch und ist auf sie zentriert") func panelHangsBelowNotch() { let g = NotchGeometry.resolve(Self.builtIn, virtualSize: Self.virtualSize) let panel = g.panelRect(for: CGSize(width: 640, height: 320)) #expect(panel.midX == g.rect.midX) // Oberkante bündig mit dem Bildschirmrand — das Panel wächst aus der // Notch heraus, es schwebt nicht darunter. #expect(panel.maxY == Self.builtIn.frame.maxY) #expect(panel.height == 320) } @Test("Panel breiter als der Bildschirm wird eingepasst statt abgeschnitten") func panelClampsToScreen() { let g = NotchGeometry.resolve(Self.builtIn, virtualSize: Self.virtualSize) let panel = g.panelRect(for: CGSize(width: 5000, height: 320)) #expect(panel.minX >= Self.builtIn.frame.minX) #expect(panel.maxX <= Self.builtIn.frame.maxX) } @Test("Panel auf dem externen Display liegt in dessen Koordinaten, nicht bei null") func panelUsesScreenOrigin() { let g = NotchGeometry.resolve(Self.external, virtualSize: Self.virtualSize) let panel = g.panelRect(for: CGSize(width: 640, height: 320)) #expect(panel.minX >= 1800) #expect(panel.maxY == 1440) } @Test("Zu hohes Panel wird auf die Bildschirmhöhe begrenzt") func panelClampsHeight() { let g = NotchGeometry.resolve(Self.builtIn, virtualSize: Self.virtualSize) let panel = g.panelRect(for: CGSize(width: 640, height: 99_999)) #expect(panel.height <= Self.builtIn.frame.height) #expect(panel.minY >= Self.builtIn.frame.minY) } }