import Testing @testable import OnyxCore // Zwei laufende Onyx-Instanzen sind kein Schönheitsfehler: jede bringt eine // eigene Zustandsmaschine, eigene Timer und eine eigene Animation auf dieselbe // Notch mit. Das Ergebnis sieht aus wie ein Ruckler und ist keiner. // // Die Regel lautet: die zuletzt gestartete Instanz gewinnt. Beim Entwickeln ist // das die frisch gebaute — die andere Reihenfolge würde bedeuten, dass man nach // jedem Build weiter die alte Fassung testet, ohne es zu merken. @Suite("Einzelinstanz") struct SingleInstanceTests { @Test("Keine andere Instanz — einfach weiterlaufen") func aloneProceeds() { #expect(SingleInstanceGuard.decide(otherPIDs: []) == .proceed) } @Test("Eine andere Instanz wird zum Beenden aufgefordert") func oneOtherIsAskedToQuit() { #expect(SingleInstanceGuard.decide(otherPIDs: [4711]) == .terminateOthers([4711])) } @Test("Mehrere andere Instanzen werden alle aufgefordert") func allOthersAreAsked() { #expect(SingleInstanceGuard.decide(otherPIDs: [1, 2, 3]) == .terminateOthers([1, 2, 3])) } @Test("Sind danach alle weg, läuft diese Instanz weiter") func proceedsWhenOthersAreGone() { #expect(SingleInstanceGuard.decideAfterTermination(remainingPIDs: []) == .proceed) } @Test("Bleibt eine übrig, tritt diese Instanz zurück statt danebenzulaufen") func standsDownWhenOthersSurvive() { // Kommt real vor: eine aus Xcode gestartete Instanz hängt im Debugger // und überlebt sogar SIGKILL. Dann ist Zurücktreten die einzig richtige // Antwort — zwei Panels auf einer Notch ist die schlechtere Lage. #expect(SingleInstanceGuard.decideAfterTermination(remainingPIDs: [4711]) == .standDown([4711])) } // MARK: - Eigene Instanz aussortieren @Test("Die eigene Instanz zählt nie als Konkurrenz") func selfIsNeverACompetitor() { let others = SingleInstanceGuard.others(from: [100, 200, 300], selfPID: 200) #expect(others == [100, 300]) } @Test("Bin ich der einzige Prozess, bleibt nichts übrig") func onlySelfLeavesNothing() { #expect(SingleInstanceGuard.others(from: [200], selfPID: 200).isEmpty) } @Test("Eine leere Prozessliste ergibt keine Konkurrenz") func emptyListIsSafe() { #expect(SingleInstanceGuard.others(from: [], selfPID: 200).isEmpty) } @Test("Die eigene PID doppelt in der Liste wird trotzdem vollständig entfernt") func duplicateSelfIsRemoved() { // Kann bei Übergabefehlern vorkommen. Sich selbst zu beenden wäre der // denkbar schlechteste Ausgang. #expect(SingleInstanceGuard.others(from: [200, 200, 300], selfPID: 200) == [300]) } // MARK: - Ganzer Ablauf @Test("Der übliche Fall: eine alte Instanz weicht, die neue übernimmt") func typicalTakeover() { let others = SingleInstanceGuard.others(from: [100, 200], selfPID: 200) #expect(SingleInstanceGuard.decide(otherPIDs: others) == .terminateOthers([100])) #expect(SingleInstanceGuard.decideAfterTermination(remainingPIDs: []) == .proceed) } }