using System.Linq; using Xunit; using ytLive.Models; using ytLive.ViewModels; namespace ytLive.Tests; /// The scoreboard is a LAYER, not a special widget: it must appear as a source type, carry /// the full-width strip geometry, be resolvable on the output path like a chat box, and hook the /// session lifecycle so its numbers are session-scoped. public class ScoreboardLayerTests { [Fact] public void The_scoreboard_is_a_real_source_with_strip_geometry_and_a_resolver() { Assert.Contains("Scoreboard", System.Enum.GetNames()); // Geometry: full width, a strip's height, bottom by default. var sources = SourceAssert.Text("ViewModels", "MainViewModel.Sources.cs"); Assert.Contains("SourceType.Scoreboard ? 1920", sources); Assert.Contains("SourceType.Scoreboard ? 56", sources); Assert.Contains("SourceType.Scoreboard ? 1024", sources); // The output resolver knows how to produce its frame (same shape as the chat box/alert box). var resolver = SourceAssert.Text("ViewModels", "MainViewModel.cs"); Assert.Contains("Source { Type: SourceType.Scoreboard } => _scoreboardPresenter?.Frame", resolver); // The PREVIEW must show the strip: its frame is a runtime frame-source and its Image needs // the visibility trigger. Missing either made every property change look inert (2026-10-30). var source = SourceAssert.Text("Models", "Source.cs"); Assert.Contains("or SourceType.AlertBox or SourceType.Scoreboard", source); Assert.Contains("IsScoreboard", SourceAssert.Text("Controls", "PreviewPane.xaml")); // Session lifecycle: every start clears the tallies. var ops = SourceAssert.Text("ViewModels", "MainViewModel.Streaming.Operations.cs"); Assert.Contains("StartScoreboardSession();", ops); } }