using AvParser.Core.Proxies; namespace AvParser.Core.Tests.Proxies; /// A clock the tests move by hand, so quarantine expiry is deterministic. internal sealed class FakeTimeProvider(DateTimeOffset start) : TimeProvider { private DateTimeOffset _now = start; public FakeTimeProvider() : this(new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero)) { } public override DateTimeOffset GetUtcNow() => _now; public void Advance(TimeSpan delta) => _now += delta; } /// A source that returns whatever the test handed it. internal sealed class FakeProxySource(ProxySourceKind kind = ProxySourceKind.Feed, params ProxyEndpoint[] endpoints) : IProxySource { public string Id { get; init; } = "fake"; public string DisplayName => "Fake source"; public ProxySourceKind Kind { get; } = kind; public List Endpoints { get; } = [.. endpoints]; public int GetCallCount { get; private set; } public Task> GetProxiesAsync(CancellationToken cancellationToken = default) { GetCallCount++; return Task.FromResult>(Endpoints.ToArray()); } } /// A probe whose verdict the test decides, per address. internal sealed class FakeProxyProbe : IProxyProbe { private readonly Dictionary _verdicts = new(StringComparer.Ordinal); /// Verdict for addresses with no explicit entry. public bool DefaultAlive { get; set; } /// How many probes were requested. public int ProbeCount { get; private set; } /// Addresses probed, in order. public List Probed { get; } = []; public FakeProxyProbe Set(ProxyEndpoint endpoint, bool alive) { _verdicts[endpoint.Key] = alive; return this; } public Task ProbeAsync( ProxyEndpoint endpoint, ProxyOptions options, CancellationToken cancellationToken = default ) { ProbeCount++; Probed.Add(endpoint.Key); var alive = _verdicts.TryGetValue(endpoint.Key, out var verdict) ? verdict : DefaultAlive; return Task.FromResult( alive ? ProxyProbeResult.Success(TimeSpan.FromMilliseconds(42)) : ProxyProbeResult.Failure("dead") ); } } /// Shorthand builders for the proxy tests. internal static class ProxyFactory { public static ProxyEndpoint Endpoint( string host, int port = 8080, ProxyProtocol protocol = ProxyProtocol.Http, int score = 0 ) => new(protocol, host, port) { Score = score }; public static ProxyEntry Entry( string host, int port = 8080, ProxyProtocol protocol = ProxyProtocol.Http, int score = 0, ProxySourceKind source = ProxySourceKind.Feed ) => new(Endpoint(host, port, protocol, score), source); }