import Testing import Foundation @testable import FlixyPlayback @Suite("Abspielliste lesen und umschreiben") struct MediaPlaylistTests { private let medien = """ #EXTM3U #EXT-X-VERSION:7 #EXT-X-TARGETDURATION:6 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-MAP:URI="hls1/main/-1.mp4" #EXTINF:6.000000, hls1/main/0.mp4 #EXTINF:6.000000, hls1/main/1.mp4 #EXTINF:5.400000, hls1/main/2.mp4 #EXT-X-ENDLIST """ private let stufen = """ #EXTM3U #EXT-X-STREAM-INF:BANDWIDTH=8000000,RESOLUTION=1920x1080 main.m3u8?level=0 #EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1280x720 main.m3u8?level=1 """ @Test("Die Schnipsel kommen in der Reihenfolge der Liste") func readsSegmentsInOrder() { let liste = MediaPlaylist(medien) #expect(liste.segments == ["hls1/main/0.mp4", "hls1/main/1.mp4", "hls1/main/2.mp4"]) #expect(!liste.isMaster) } /// Die beiden Listenarten sehen sich ähnlich und meinen Verschiedenes. /// Wer sie verwechselt, lädt Abspiellisten vor statt Bild. @Test("Eine Liste von Stufen ist keine Liste von Schnipseln") func tellsMasterFromMedia() { #expect(MediaPlaylist(stufen).isMaster) #expect(MediaPlaylist(stufen).segments.count == 2) #expect(!MediaPlaylist(medien).isMaster) } /// **Die teuerste Stelle.** Eine Liste, die stellenweise am Speicher /// vorbeizeigt, ergibt einen Film, der nur manchmal hakt — und so etwas /// findet man im laufenden Bild nicht. @Test("Umgeschrieben werden Adressen, sonst nichts") func rewritesOnlyReferences() { let neu = MediaPlaylist(medien).rewritingReferences { "http://127.0.0.1:1234/s/\($0)" } #expect(neu.contains("http://127.0.0.1:1234/s/hls1/main/0.mp4")) #expect(neu.contains("http://127.0.0.1:1234/s/hls1/main/2.mp4")) // Anweisungen bleiben, wie sie waren — auch die mit einer Adresse // **darin**, die wir nicht verstehen. #expect(neu.contains("#EXT-X-TARGETDURATION:6")) #expect(neu.contains("#EXT-X-MAP:URI=\"hls1/main/-1.mp4\"")) #expect(neu.contains("#EXT-X-ENDLIST")) #expect(neu.hasPrefix("#EXTM3U")) } @Test("Die Zeilenzahl bleibt gleich") func keepsStructure() { let neu = MediaPlaylist(medien).rewritingReferences { $0 } #expect(neu.components(separatedBy: "\n").count == medien.components(separatedBy: "\n").count) } @Test("Eine vollständige Liste ist als solche zu erkennen") func knowsWhenComplete() { #expect(MediaPlaylist(medien).isComplete) // Ohne Schlussmarke: ein laufender Sender, die Liste wächst noch. #expect(!MediaPlaylist(medien.replacingOccurrences(of: "#EXT-X-ENDLIST", with: "")).isComplete) } @Test("Die Schnipseldauer wird gelesen") func readsTargetDuration() { #expect(MediaPlaylist(medien).targetDuration == .seconds(6)) #expect(MediaPlaylist(stufen).targetDuration == nil) } @Test("Eine leere Eingabe ergibt eine leere Liste, keinen Absturz") func emptyIsEmpty() { #expect(MediaPlaylist("").segments.isEmpty) #expect(MediaPlaylist("").rewritingReferences { $0 } == "") } }