Files
Flaro/Packages/FlixyKit/Tests/FlixyPlaybackTests/StallLedgerTests.swift
T
ScarriffleandClaude Opus 5 e324a474fd Watchdog heisst Watchdog, Engine heisst Engine
Eingedeutschte Fachbegriffe in den Kommentaren — „Wachhund" für
Watchdog, „Motor" für Engine. Das liest sich albern und ist unklarer als
das Original; niemand sagt Wachhund, wenn er einen Watchdog meint.

Acht Stellen berichtigt. Gewöhnliche Sprache bleibt deutsch, der Stil
der Kommentare ändert sich nicht.

Dazu die Plex-Leiter messbar gemacht: `--leiter` baut dieselbe Anfrage
zweimal, mit und ohne `autoAdjustQuality=1`, und zählt die Stufen. Die
Zeile steht seit dem Umbau im Code und war nie geprüft — genau die Art
ungeprüfter Annahme über Serververhalten, die bei Jellyfin vier Runden
gekostet hat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 17:47:31 +02:00

90 lines
3.4 KiB
Swift

import Testing
import Foundation
@testable import FlixyPlayback
@Suite("Rückler-Buchführung")
struct StallLedgerTests {
/// Der Fall, wegen dem es den Typ gibt.
///
/// Zehn Rückler à dreißig Sekunden lösten beim alten Watchdog nichts aus,
/// weil er sich bei jedem Erholen zurücksetzte. Hier muss sichtbar
/// werden, dass die Wiedergabe unbrauchbar ist.
@Test("Viele kurze Rückler bleiben sichtbar")
func manyShortStallsAreVisible() {
var ledger = StallLedger(window: .seconds(180))
// Alle 20 s ein Rückler von 5 s, drei Minuten lang.
for step in 1...9 {
ledger.record(.init(endedAt: .seconds(step * 20), length: .seconds(5)))
}
let now = Duration.seconds(180)
#expect(ledger.count(at: now) == 9)
// 45 s Warten in 180 s Fenster.
#expect(ledger.share(at: now) > 0.2)
#expect(ledger.share(at: now) < 0.3)
}
@Test("Was aus dem Fenster fällt, zählt nicht mehr")
func oldEpisodesFallOut() {
var ledger = StallLedger(window: .seconds(180))
ledger.record(.init(endedAt: .seconds(10), length: .seconds(30)))
#expect(ledger.count(at: .seconds(60)) == 1)
// Weit hinter dem Fenster: vergessen.
#expect(ledger.count(at: .seconds(300)) == 0)
#expect(ledger.share(at: .seconds(300)) == 0)
}
/// Am Anfang ist das Fenster noch nicht voll — dann gegen die tatsächlich
/// vergangene Zeit rechnen, sonst sieht ein früher Rückler harmlos aus.
@Test("Früh im Film zählt die vergangene Zeit, nicht das ganze Fenster")
func earlyStallsAreNotDiluted() {
var ledger = StallLedger(window: .seconds(180))
ledger.record(.init(endedAt: .seconds(20), length: .seconds(5)))
let share = ledger.share(at: .seconds(20))
// 5 s von 20 s, nicht 5 s von 180 s.
#expect(share > 0.2)
#expect(share < 0.3)
}
@Test("Der laufende Rückler zählt mit")
func ongoingStallCounts() {
var ledger = StallLedger(window: .seconds(180))
ledger.record(.init(endedAt: .seconds(60), length: .seconds(10)))
let without = ledger.share(at: .seconds(180))
let with = ledger.share(at: .seconds(180), ongoing: .seconds(20))
#expect(with > without)
}
/// Ein einzelner langer Rückler ist eine andere Aussage als viele kurze.
@Test("Der längste Einzelfall lässt sich getrennt ablesen")
func longestIsSeparate() {
var ledger = StallLedger(window: .seconds(180))
ledger.record(.init(endedAt: .seconds(30), length: .seconds(2)))
ledger.record(.init(endedAt: .seconds(60), length: .seconds(18)))
ledger.record(.init(endedAt: .seconds(90), length: .seconds(3)))
#expect(ledger.longest(at: .seconds(120)) == .seconds(18))
#expect(ledger.count(at: .seconds(120)) == 3)
}
@Test("Eine ruhige Wiedergabe meldet nichts")
func quietPlaybackIsQuiet() {
let ledger = StallLedger()
#expect(ledger.count(at: .seconds(600)) == 0)
#expect(ledger.share(at: .seconds(600)) == 0)
#expect(ledger.longest(at: .seconds(600)) == .zero)
}
@Test("Der Anteil übersteigt nie eins")
func shareIsBounded() {
var ledger = StallLedger(window: .seconds(60))
// Absurd: mehr Wartezeit als Fenster.
ledger.record(.init(endedAt: .seconds(30), length: .seconds(200)))
#expect(ledger.share(at: .seconds(60)) == 1)
}
}