Files
Flaro/Packages/FlaroKit/Tests/FlaroServerKitTests/Hilfsmittel.swift
T
ScarriffleandClaude Opus 5 693a6cc867 Cookie heisst Cookie
„Keks", „Keksglas", „Kekse" — eingedeutscht, wo es nichts zu
verdeutschen gibt. Ein Cookie ist ein Cookie; wer danach sucht, sucht
nicht nach Keksen, und wer den Quelltext liest, liest daneben die
Schnittstelle, in der es `HTTPCookieStorage` heisst.

Betrifft Kommentare und Prüfungsnamen, kein Verhalten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-10 20:42:29 +02:00

105 lines
4.2 KiB
Swift

import Foundation
@testable import FlaroServerKit
/// Ein Transport, der vorbereitete Antworten gibt und mitschreibt.
///
/// Dieselbe Trennung wie bei Jellyfin: Prüfungen brauchen keinen Server,
/// sondern eine Antwort und die Frage, die gestellt wurde.
final class Attrappe: FlaroTransport, @unchecked Sendable {
/// Antworten je Pfad. Der erste Treffer gewinnt — so kann eine Prüfung
/// `/api/v1/movies` und `/api/v1/movies/{id}` getrennt bedienen.
private let antworten: [(pfad: String, status: Int, rumpf: String)]
private let sperre = NSLock()
private var protokoll: [URLRequest] = []
init(_ antworten: [(pfad: String, status: Int, rumpf: String)]) {
self.antworten = antworten
}
convenience init(rumpf: String, status: Int = 200) {
self.init([("", status, rumpf)])
}
var anfragen: [URLRequest] { sperre.withLock { protokoll } }
var letzte: URLRequest? { anfragen.last }
func anfrage(auf pfad: String) -> URLRequest? {
anfragen.last { $0.url?.path == pfad }
}
func rumpf(von pfad: String) -> [String: Any]? {
guard let daten = anfrage(auf: pfad)?.httpBody else { return nil }
return try? JSONSerialization.jsonObject(with: daten) as? [String: Any]
}
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
sperre.withLock { protokoll.append(request) }
let pfad = request.url?.path ?? ""
let treffer = antworten.first { $0.pfad.isEmpty || pfad.hasSuffix($0.pfad) || pfad == $0.pfad }
?? ("", 404, "")
return (
Data(treffer.rumpf.utf8),
HTTPURLResponse(url: request.url!, statusCode: treffer.status,
httpVersion: nil, headerFields: nil)!
)
}
}
/// Ein Cookieglas, das nur mitschreibt.
///
/// Der Speicher des Systems anzufassen hiesse, dass eine Prüfung die nächste
/// beeinflusst — und auf einem Entwicklerrechner auch den Browser.
final class Cookieglas: FlaroCookieJar, @unchecked Sendable {
private let sperre = NSLock()
private var inhalt: [HTTPCookie] = []
var cookies: [HTTPCookie] { sperre.withLock { inhalt } }
func store(_ cookie: HTTPCookie) { sperre.withLock { inhalt.append(cookie) } }
func removeCookie(named name: String, host: String) {
sperre.withLock { inhalt.removeAll { $0.name == name } }
}
}
enum Proben {
static let adresse = URL(string: "http://nas:8080")!
static let kennung = FlaroIdentity(deviceName: "Prüfgerät", deviceID: "geraet-1")
/// Ein Film mit zwei Tonspuren — der Fall, um den es geht.
static let film = """
{
"id": "film-1", "title": "Der Untergang", "year": 2004,
"overview": "Berlin, April 1945.",
"posterImage": "aaa", "backdropImage": "bbb",
"files": [{
"id": "datei-1", "fileName": "Der Untergang (2004).mkv",
"sizeBytes": 9000000000, "container": "matroska", "durationSeconds": 9360.0,
"streams": [
{"index":0,"kind":"Video","codec":"h264","language":null,"title":null,
"isDefault":true,"isForced":false,"channels":null,"width":1920,"height":1080},
{"index":1,"kind":"Audio","codec":"ac3","language":"deu","title":"Deutsch",
"isDefault":true,"isForced":false,"channels":6,"width":null,"height":null},
{"index":2,"kind":"Audio","codec":"ac3","language":"deu","title":"Audiodeskription",
"isDefault":false,"isForced":false,"channels":2,"width":null,"height":null},
{"index":3,"kind":"Subtitle","codec":"subrip","language":"deu","title":"Deutsch",
"isDefault":false,"isForced":false,"channels":null,"width":null,"height":null}
]
}],
"state": {"positionSeconds":300.0,"runtimeSeconds":9360.0,"watched":false,
"playCount":0,"favourite":false,"rating":null,"dismissed":false,
"lastPlayedAt":"2026-10-03T19:25:04.5209555+00:00"}
}
"""
static let info = """
{"version":"0.1.0","serverName":"Wohnzimmer","needsSetup":false,
"attributions":[{"text":"This product uses TMDB","logoUrl":"https://x/t.svg","url":"https://x"}]}
"""
static let anmeldung = """
{"token":"geheim-123","user":{"id":"u1","userName":"guido","isAdministrator":true}}
"""
}