using System.Reflection; using Xunit; using ytLive.ViewModels; namespace ytLive.Tests; /// The scoreboard's look and its eight fact switches live in the LAYER PROPERTIES, and the /// panel must use the app's widgets — a hand-painted control is the TASK 58/63 defect, and the /// guard that catches it is here because the type-based sweep cannot see a bespoke picker. public class ScoreboardPropertiesTests { [Fact] public void The_scoreboard_properties_are_themed_controls_bound_to_the_layer_surface() { var panel = SourceAssert.Text("Controls", "LeftPanel.xaml"); // Gated on the selected layer being a scoreboard. Assert.Contains("SelectedElement.IsScoreboard", panel); // Signed out: the block is inert with a one-line explanation — EXCEPT in a DEBUG build, where // CanUseScoreboard is true so the strip can be previewed without an account. var block = panel[panel.IndexOf("Scoreboard config", System.StringComparison.Ordinal)..]; block = block[..block.IndexOf("", System.StringComparison.Ordinal)]; Assert.Contains("IsEnabled=\"{Binding CanUseScoreboard}\"", block); Assert.Contains("Sign in to YouTube to use the scoreboard.", block); Assert.Contains("CanUseScoreboard, Converter={StaticResource InverseBoolToVis}", block); // Defaults the creator asked for, and readouts that actually move. Assert.Contains("Background", block); Assert.DoesNotContain("Background plate", block); Assert.Contains("ScoreboardFontSizeLabel", block); // "24 px", not a bare number var vm = SourceAssert.Text("ViewModels", "MainViewModel.Scoreboard.cs"); Assert.Contains("OnPropertyChanged(nameof(ScoreboardBackgroundOpacity));", vm); Assert.Contains("OnPropertyChanged(nameof(ScoreboardFontSize));", vm); // Dev-only labels are ORANGE, so a development affordance cannot pass for product. Assert.Contains("Simulate (dev)", block); Assert.Contains("Brush.Attention", block); // Scroll speed: a real dial, persisted, with its range owned by the presenter. Assert.Contains("ScoreboardScrollSpeed", block); Assert.Contains("Minimum=\"20\" Maximum=\"200\"", block); Assert.Contains("Scoreboard.ScrollSpeed", SourceAssert.Text("Services", "LayoutStore.Settings.cs")); // The master switch sits in the same panel: off hides the strip and stops the polling. Assert.Contains("ScoreboardEnabled", panel); // The eight fact switches. foreach (var binding in new[] { "ScoreboardShowSubscribers", "ScoreboardShowWatchHours", "ScoreboardShowSuperChats", "ScoreboardShowNewMembers", "ScoreboardShowMilestones", "ScoreboardShowLastMember", "ScoreboardShowLastSuperChat", "ScoreboardShowLastGift", }) Assert.Contains(binding, panel); // Look controls: text colour, plate colour, plate opacity, text size. foreach (var binding in new[] { "ScoreboardTextColor", "ScoreboardBackgroundColor", "ScoreboardBackgroundOpacity", "ScoreboardFontSize", }) Assert.Contains(binding, panel); // Theme widgets only: colour pickers use YtComboBox and the property-panel toggles use // the themed pill-switch style. Assert.Contains("Style=\"{StaticResource YtComboBox}\"", block); Assert.Contains("Style=\"{StaticResource PropertyPillCheck}\"", block); Assert.DoesNotContain("ContextMenu", block); // The VM surface exists for every binding above (a typo would bind to nothing silently). var type = typeof(MainViewModel); foreach (var name in new[] { "ScoreboardTextColor", "ScoreboardBackgroundColor", "ScoreboardBackgroundOpacity", "ScoreboardFontSize", "ScoreboardColorOptions", "ScoreboardShowSubscribers", "ScoreboardEnabled", "CanUseScoreboard", "ScoreboardScrollSpeed", }) Assert.NotNull(type.GetProperty(name)); } }