using System; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using Microsoft.Data.Sqlite; using Xunit; using ytLive.Models; using ytLive.ViewModels; namespace ytLive.Tests; /// /// TASK 47 Good Dog (take three, 2026-09-26): the alert box's frame must be /// DRAWN by the preview pane. The 14:26 and 14:28 live runs on build 90 proved /// everything up to the last hop: Alert preview: frame=680x200 a255 and /// Output resolver: frame 680x200 playing=True every second for the whole /// clip — a real, opaque, correctly-sized frame (the shipped llama asset decodes /// bright, 1280x720 h264) handed to the canvas — and the box stayed blank. /// Root cause: the preview's per-element Image only becomes Visible for /// IsImageSource / IsChatBox / IsWebSource / IsWebcam, so an AlertBox's Image /// stayed Collapsed and the bound frame was never rendered. /// [Collection("RealApp")] public sealed class AlertBoxPreviewVisibilityTests { private readonly RealAppHost _app; public AlertBoxPreviewVisibilityTests(RealAppHost app) => _app = app; [Fact] public void AlertBox_HandedAFrame_IsDrawnInThePreviewPane() { _app.Run(Run); } private void Run() { var tempDb = Path.Combine(Path.GetTempPath(), $"ytLlive-test-{Guid.NewGuid():N}.db"); MainViewModel.LayoutPathOverride = tempDb; var window = new MainWindow(); var vm = (MainViewModel)window.DataContext; try { window.Show(); window.UpdateLayout(); var box = new Source { Type = SourceType.AlertBox, Name = "Stream Alerts", X = 100, Y = 100, Width = 320, Height = 180, }; vm.StagedScene!.Elements.Add(box); vm.SelectedElement = box; // Exactly what the layer writes onto the source every tick while a clip // plays: a real, opaque, box-sized frame. box.VideoImageSource = SolidFrame(320, 180); window.UpdateLayout(); var pane = (UserControl)window.FindName("PreviewPane")!; var image = FindImageShowing(pane, box.VideoImageSource); Assert.True(image != null, "the preview pane never bound the alert box's frame to an Image"); Assert.Equal(Visibility.Visible, image!.Visibility); Assert.True(image.IsVisible, "the alert box's Image is Collapsed, so the frame is never rendered"); } finally { window.Close(); MainViewModel.LayoutPathOverride = null; SqliteConnection.ClearAllPools(); try { File.Delete(tempDb); } catch { /* best-effort cleanup */ } } } private static WriteableBitmap SolidFrame(int w, int h) { var bitmap = new WriteableBitmap(w, h, 96, 96, PixelFormats.Bgra32, null); var pixels = new byte[w * h * 4]; for (var i = 0; i < pixels.Length; i += 4) { pixels[i] = 40; // B pixels[i + 1] = 90; // G pixels[i + 2] = 200; // R pixels[i + 3] = 255; // opaque } bitmap.WritePixels(new Int32Rect(0, 0, w, h), pixels, w * 4, 0); return bitmap; } private static Image? FindImageShowing(DependencyObject parent, ImageSource? source) => Walk(parent, e => e is Image i && ReferenceEquals(i.Source, source)) as Image; private static DependencyObject? Walk(DependencyObject parent, Func predicate) { for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); if (predicate(child)) return child; var found = Walk(child, predicate); if (found != null) return found; } return null; } }