import Testing import CoreAudio @testable import AudioProvider // Chrome gibt seinen Ton über einen Hilfsprozess aus. In der Liste standen // deshalb „Google Chrome" und „Google Chrome Helper" nebeneinander — zwei // Regler für dasselbe Programm, und wer den einen zieht, hört den anderen. private func process(_ bundleID: String, name: String, id: UInt32, playing: Bool = false) -> AudioProcess { AudioProcess(objectID: AudioObjectID(id), pid: pid_t(id), bundleID: bundleID, name: name, isPlaying: playing) } @Suite("Programme zusammenfassen") struct ProcessGroupTests { @Test("Hilfsprozess und Programm werden eine Zeile") func helperJoinsItsApp() { let groups = AudioProcessGroup.group([ process("com.google.Chrome", name: "Google Chrome", id: 1), process("com.google.Chrome.helper", name: "Google Chrome Helper", id: 2), ]) #expect(groups.count == 1) #expect(groups.first?.bundleID == "com.google.Chrome") #expect(groups.first?.processes.count == 2) } @Test("Der Name kommt vom Programm, nicht vom Helfer") func nameComesFromTheApp() { let groups = AudioProcessGroup.group([ process("com.google.Chrome.helper", name: "Google Chrome Helper", id: 2), process("com.google.Chrome", name: "Google Chrome", id: 1), ]) #expect(groups.first?.name == "Google Chrome") } @Test("Ohne das Programm selbst trägt der Helfer den Namen") func helperAloneKeepsItsName() { // Chrome kann Ton ausgeben, ohne dass der Hauptprozess selbst als // Tonquelle auftaucht. Dann ist der Helfer alles, was da ist. let groups = AudioProcessGroup.group([ process("com.google.Chrome.helper", name: "Google Chrome Helper", id: 2), ]) #expect(groups.count == 1) #expect(groups.first?.bundleID == "com.google.Chrome") } @Test("Verschiedene Programme bleiben getrennt") func differentAppsStayApart() { let groups = AudioProcessGroup.group([ process("com.spotify.client", name: "Spotify", id: 1), process("com.google.Chrome", name: "Google Chrome", id: 2), ]) #expect(groups.count == 2) } @Test("Spielt einer, spielt die Gruppe") func groupPlaysIfAnyPlays() { // Der Ton kommt aus dem Helfer; der Hauptprozess schweigt. Die Zeile // muss trotzdem als spielend gelten, sonst verschwindet sie. let groups = AudioProcessGroup.group([ process("com.google.Chrome", name: "Google Chrome", id: 1, playing: false), process("com.google.Chrome.helper", name: "Helper", id: 2, playing: true), ]) #expect(groups.first?.isPlaying == true) } @Test("Mehrere Helfer landen alle in derselben Zeile") func manyHelpersOneRow() { // Chrome hat je Tab einen. Fünfzehn Regler für einen Browser wären // keine Auskunft, sondern eine Zumutung. let groups = AudioProcessGroup.group((1...5).map { process("com.google.Chrome.helper", name: "Helper", id: UInt32($0)) }) #expect(groups.count == 1) #expect(groups.first?.processes.count == 5) } @Test("Die Reihenfolge bleibt stabil") func orderIsStable() { // Sonst springen die Zeilen bei jeder Messung umher, weil Core Audio // keine Reihenfolge zusagt. let input = [process("b.app", name: "B", id: 2), process("a.app", name: "A", id: 1)] #expect(AudioProcessGroup.group(input).map(\.name) == ["A", "B"]) } }