using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; namespace Jellyfin.Plugin.Floatplane.Tests; /// Maps request URLs (prefix match on path, or a predicate) to canned responses and records requests. internal sealed class FakeHttpHandler : HttpMessageHandler { private readonly List<(Func Match, Func Respond)> _routes = new(); public List Requests { get; } = new(); public FakeHttpHandler On(string pathPrefix, Func respond) { _routes.Add((r => r.RequestUri!.AbsolutePath.StartsWith(pathPrefix, StringComparison.Ordinal), respond)); return this; } public FakeHttpHandler On(Func match, Func respond) { _routes.Add((match, respond)); return this; } public static HttpResponseMessage Json(string body, HttpStatusCode status = HttpStatusCode.OK) => new(status) { Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json") }; protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Requests.Add(request); foreach (var (match, respond) in _routes) { if (match(request)) { var response = respond(request); response.RequestMessage = request; return Task.FromResult(response); } } var notFound = new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request, Content = new StringContent("no route for " + request.RequestUri) }; return Task.FromResult(notFound); } } /// Mirrors the registrator: one named client with the plugin User-Agent. internal sealed class FakeHttpClientFactory : IHttpClientFactory { private readonly HttpMessageHandler _handler; public FakeHttpClientFactory(HttpMessageHandler handler) { _handler = handler; } public HttpClient CreateClient(string name) { var client = new HttpClient(_handler, disposeHandler: false); client.DefaultRequestHeaders.UserAgent.ParseAdd(Plugin.UserAgent); return client; } }