import Testing @testable import AudioProvider // Core Audio meldet Prozesse, nicht Programme. Was dort ankommt, heißt // `com.google.Chrome.helper` oder `com.apple.WebKit.GPU` — Kennungen, die in // einem Mischpult nichts zu suchen haben. Wer „Spotify leiser" sucht, sucht // nach „Spotify". @Suite("Programmnamen") struct ProcessNameTests { @Test("Aus einer Kennung wird ein lesbarer Name") func plainIdentifier() { #expect(ProcessNaming.fallbackName(for: "com.spotify.client") == "Spotify") } @Test("Hilfsprozesse werden ihrem Programm zugeordnet") func helpersMapToParent() { // Chromes Ton kommt aus einem Hilfsprozess. Ihn als // „com.google.Chrome.helper" zu zeigen wäre technisch richtig und // praktisch nutzlos. #expect(ProcessNaming.parentBundleID(for: "com.google.Chrome.helper") == "com.google.Chrome") #expect(ProcessNaming.parentBundleID(for: "com.google.Chrome.helper.Renderer") == "com.google.Chrome") } @Test("Weitere übliche Endungen von Hilfsprozessen") func knownHelperSuffixes() { #expect(ProcessNaming.parentBundleID(for: "net.whatsapp.WhatsApp.ServiceExtension") == "net.whatsapp.WhatsApp") #expect(ProcessNaming.parentBundleID(for: "com.example.App.Helper") == "com.example.App") } @Test("Eine gewöhnliche Kennung bleibt unverändert") func plainIdentifierIsUntouched() { #expect(ProcessNaming.parentBundleID(for: "com.spotify.client") == "com.spotify.client") } @Test("Der Hilfsprozess einer Komponente zeigt die Komponente") func helperShowsItsComponent() { // `.GPU` ist eine Hilfsprozess-Endung, also bleibt WebKit übrig. Das // ist die nützlichere Auskunft: „GPU" allein sagt niemandem etwas. #expect(ProcessNaming.fallbackName(for: "com.apple.WebKit.GPU") == "WebKit") #expect(ProcessNaming.fallbackName(for: "pro.betterdisplay.BetterDisplay") == "BetterDisplay") } @Test("Eine Kennung ohne Punkte bleibt sie selbst") func singleComponent() { #expect(ProcessNaming.fallbackName(for: "systemsoundserverd") == "systemsoundserverd") } @Test("Eine leere Kennung ergibt keinen leeren Namen") func emptyIsHandled() { #expect(!ProcessNaming.fallbackName(for: "").isEmpty) } } @Suite("Sichtbarkeit im Mischpult") struct ProcessVisibilityTests { @Test("Was gerade Ton ausgibt, wird gezeigt") func playingIsVisible() { #expect(ProcessVisibility.shouldShow(isPlaying: true, secondsSinceHeard: nil, isManaged: false)) } @Test("Was nie Ton ausgegeben hat, wird nicht gezeigt") func neverHeardIsHidden() { // Der eigentliche Punkt: Core Audio führt Dutzende Systemdienste, die // theoretisch Ton ausgeben könnten. In einem Mischpult sind sie nur // Rauschen. #expect(!ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: nil, isManaged: false)) } @Test("Kurz nach dem Verstummen bleibt es sichtbar") func recentlyHeardStaysVisible() { // Sonst verschwindet Spotify beim Pausieren aus der Liste, und man kann // die Lautstärke genau dann nicht mehr einstellen, wenn man es will. #expect(ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: 30, isManaged: false)) } @Test("Lange danach verschwindet es") func longSilentDisappears() { #expect(!ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: 600, isManaged: false)) } @Test("Ein geregeltes Programm bleibt immer sichtbar") func managedIsAlwaysVisible() { // Wer die Lautstärke von etwas eingestellt hat, muss sie auch wieder // zurücknehmen können — auch wenn gerade nichts läuft. #expect(ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: 99999, isManaged: true)) } }