using System.Net; using System.Text; using System.Xml.Linq; using Xunit; using ytLive.Models; using ytLive.Services; using ytLive.ViewModels; namespace ytLive.Tests; /// Creator ruling 2026-10-09: a PRIVATE broadcast ends like a recording — Enter keeps /// it on YouTube, Escape deletes it. public class PrivateBroadcastCloseOutTests { private sealed class Handler : HttpMessageHandler { public string Privacy = "private"; public readonly List Requests = new(); protected override Task SendAsync(HttpRequestMessage request, CancellationToken ct) { Requests.Add($"{request.Method.Method} {request.RequestUri!.PathAndQuery}"); if (request.Method == HttpMethod.Delete) return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NoContent)); var body = "{\"items\":[{\"id\":\"BC1\",\"status\":{\"privacyStatus\":\"" + Privacy + "\",\"lifeCycleStatus\":\"complete\"}}]}"; return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(body, Encoding.UTF8, "application/json"), }); } } private static YouTubeStreamService Service(Handler handler) { var auth = new YouTubeAuthService("test-id", "test-secret"); auth.SetSession(new YouTubeChannel { AccessToken = "acc", TokenExpiry = DateTime.UtcNow.AddHours(1) }); return new YouTubeStreamService(auth, new HttpClient(handler)); } [Fact] public async Task Private_Broadcast_Escape_Deletes_Enter_Keeps_Public_Is_Never_Asked() { // Escape / Delete → the video is deleted from YouTube. var h = new Handler(); var (outcome, error) = await MainViewModel.ClosePrivateBroadcastAsync(Service(h), "BC1", askKeep: () => false); Assert.Equal(MainViewModel.PrivateBroadcastOutcome.Deleted, outcome); Assert.Null(error); Assert.Contains(h.Requests, r => r.StartsWith("DELETE /youtube/v3/videos?id=BC1")); // Enter / Keep → nothing is deleted. h = new Handler(); (outcome, _) = await MainViewModel.ClosePrivateBroadcastAsync(Service(h), "BC1", askKeep: () => true); Assert.Equal(MainViewModel.PrivateBroadcastOutcome.Kept, outcome); Assert.DoesNotContain(h.Requests, r => r.StartsWith("DELETE")); // Not private (changed mid-stream) → no prompt, nothing deleted. h = new Handler { Privacy = "public" }; var asked = false; (outcome, _) = await MainViewModel.ClosePrivateBroadcastAsync(Service(h), "BC1", askKeep: () => asked = true); Assert.Equal(MainViewModel.PrivateBroadcastOutcome.NotPrivate, outcome); Assert.False(asked); Assert.DoesNotContain(h.Requests, r => r.StartsWith("DELETE")); // The prompt itself: Enter = Keep (IsDefault), Escape = Delete (IsCancel). XNamespace x = "http://schemas.microsoft.com/winfx/2006/xaml"; var doc = XDocument.Load(SourceAssert.RepoPath("KeepBroadcastDialog.xaml")); XElement Named(string name) => doc.Descendants().Single(e => (string?)e.Attribute(x + "Name") == name); Assert.Equal("True", (string?)Named("KeepBroadcastButton").Attribute("IsDefault")); Assert.Equal("True", (string?)Named("DeleteBroadcastButton").Attribute("IsCancel")); } }