using System.Net; using System.Text; using Xunit; using ytLive.Models; using ytLive.Services; namespace ytLive.Tests; public class YouTubeAuthServiceTests { private sealed class FakeHandler : HttpMessageHandler { private readonly string _tokenResponse; private readonly string _channelResponse; public FakeHandler(string tokenResponse, string channelResponse) { _tokenResponse = tokenResponse; _channelResponse = channelResponse; } protected override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { var isToken = request.RequestUri!.PathAndQuery.Contains("/token"); var body = isToken ? _tokenResponse : _channelResponse; return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(body, Encoding.UTF8, "application/json"), }); } } private static YouTubeAuthService CreateService(string tokenResponse, string channelResponse) => new("test-id", "test-secret", new HttpClient(new FakeHandler(tokenResponse, channelResponse))); [Fact] public async Task ExchangeCodeForToken_MockServer_ParsesChannel() { var service = CreateService( """{"access_token":"acc-123","refresh_token":"ref-123","expires_in":3600}""", """{"items":[{"id":"UC123","snippet":{"title":"Test Channel","thumbnails":{"default":{"url":"http://example/thumb.jpg"}}}}]}"""); var channel = await service.ExchangeCodeForToken("auth-code", "http://localhost:8765/oauth2/callback"); Assert.NotNull(channel); Assert.Equal("UC123", channel!.ChannelId); Assert.Equal("Test Channel", channel.DisplayName); Assert.Equal("http://example/thumb.jpg", channel.ProfileImageUrl); Assert.Equal("acc-123", channel.AccessToken); Assert.Equal("ref-123", channel.RefreshToken); Assert.InRange(channel.TokenExpiry, DateTime.UtcNow.AddSeconds(3590), DateTime.UtcNow.AddSeconds(3610)); } [Fact] public async Task RefreshToken_MockServer_UpdatesAccessTokenAndExpiry() { var service = CreateService( """{"access_token":"new-acc","expires_in":3600}""", """{"items":[]}"""); service.SetSession(new YouTubeChannel { RefreshToken = "ref-123", TokenExpiry = DateTime.UtcNow.AddMinutes(-5), }); var ok = await service.RefreshToken(); Assert.True(ok); Assert.Equal("new-acc", service.CurrentChannel!.AccessToken); Assert.InRange(service.CurrentChannel.TokenExpiry, DateTime.UtcNow.AddSeconds(3590), DateTime.UtcNow.AddSeconds(3610)); } [Fact] public void ClearSession_DropsCurrentChannel() { var service = CreateService("""{"access_token":"a","refresh_token":"r","expires_in":3600}""", """{"items":[]}"""); service.SetSession(new YouTubeChannel { DisplayName = "Test Channel" }); service.ClearSession(); Assert.Null(service.CurrentChannel); } }