import Foundation import Testing @testable import PlexKit @Suite("Transcode-Anfrage") struct TranscodeRequestTests { private func value(_ request: TranscodeRequest, _ name: String) -> String? { request.queryItems.first { $0.name == name }?.value } @Test("Der Pfad zeigt auf den Titel, nicht auf die Datei") func pathPointsAtMetadata() { // Plex erwartet hier die Metadaten-Adresse. Gibt man den Dateipfad an, // antwortet der Transcoder mit 404. let request = TranscodeRequest(ratingKey: "45231", isLocal: true) #expect(value(request, "path") == "/library/metadata/45231") } @Test("Umpacken ist erlaubt, DirectPlay ausdrücklich nicht") func allowsDirectStreamButNotDirectPlay() { // directStream=1 lässt Plex nur den Container wechseln, wenn der // Bildcodec passt — das spart die Neukodierung. directPlay=0, weil // diese Frage der PlaybackDecider bereits entschieden hat. let request = TranscodeRequest(ratingKey: "1", isLocal: true) #expect(value(request, "directStream") == "1") #expect(value(request, "directPlay") == "0") } @Test("Ohne fastSeek müsste der Transcoder beim Springen von vorn beginnen") func enablesFastSeek() { #expect(value(TranscodeRequest(ratingKey: "1", isLocal: true), "fastSeek") == "1") } @Test("Die Bitratengrenze bringt eine passende Qualitätsstufe mit") func bitrateCarriesQuality() { // Ohne videoQuality ignoriert Plex die Grenze bei manchen Fassungen. let request = TranscodeRequest(ratingKey: "1", maximumBitrate: 4_000, isLocal: false) #expect(value(request, "maxVideoBitrate") == "4000") #expect(value(request, "videoQuality") != nil) } @Test("Höhere Bitraten ergeben höhere Qualitätsstufen") func qualityRisesWithBitrate() { func quality(_ bitrate: Int) -> Int { Int(value(TranscodeRequest(ratingKey: "1", maximumBitrate: bitrate, isLocal: true), "videoQuality") ?? "0")! } #expect(quality(2_000) < quality(8_000)) #expect(quality(8_000) < quality(20_000)) #expect(quality(20_000) <= 100) } @Test("Ohne Grenze steht keine Bitrate in der Anfrage") func noBitrateWhenUnlimited() { // Ein leerer Wert ist für Plex nicht dasselbe wie ein fehlender — er // würde als Grenze von null gelesen. let request = TranscodeRequest(ratingKey: "1", isLocal: true) #expect(value(request, "maxVideoBitrate") == nil) #expect(value(request, "videoQuality") == nil) } @Test("Lokal und außer Haus werden unterschieden") func distinguishesLocation() { #expect(value(TranscodeRequest(ratingKey: "1", isLocal: true), "location") == "lan") #expect(value(TranscodeRequest(ratingKey: "1", isLocal: false), "location") == "wan") } @Test("Die Sitzungskennung steht in beiden Feldern") func sessionAppearsTwice() { // Plex erwartet sie sowohl als `session` als auch als // `X-Plex-Session-Identifier`. Fehlt eines, lässt sich der Transcoder // später nicht gezielt anhalten — und er rechnet minutenlang weiter. let request = TranscodeRequest(ratingKey: "1", isLocal: true, sessionIdentifier: "sitzung-1") #expect(value(request, "session") == "sitzung-1") #expect(value(request, "X-Plex-Session-Identifier") == "sitzung-1") } @Test("Untertitel werden nur eingebrannt, wenn eine Spur gewählt ist") func subtitlesOnlyWhenRequested() { let without = TranscodeRequest(ratingKey: "1", isLocal: true) #expect(value(without, "subtitles") == nil) let with = TranscodeRequest(ratingKey: "1", isLocal: true, subtitleStreamID: 310_024) #expect(value(with, "subtitles") == "burn") #expect(value(with, "subtitleStreamID") == "310024") } } @Suite("Dauer in Plex-Einheiten") struct DurationConversionTests { @Test("Millisekunden werden ganzzahlig gerechnet") func millisecondsAreWholeNumbers() { #expect(Duration.seconds(90).milliseconds == 90_000) #expect(Duration.milliseconds(4_892_000).milliseconds == 4_892_000) #expect(Duration.zero.milliseconds == 0) } @Test("Sekunden als Gleitkommazahl") func secondsAsDouble() { #expect(abs(Duration.milliseconds(1_500).seconds - 1.5) < 0.0001) } }