using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using Xunit; namespace ytLive.Tests; /// A missing {StaticResource} key does not fail the build — WPF substitutes /// DependencyProperty.UnsetValue and throws at the next layout pass. That is exactly how /// the app crashed on 2026-10-30: the token conversion deleted YtSliderKnobHoverBrush /// while two slider triggers still asked for it, so the first slider the creator touched /// (the new socials opacity slider) killed the app inside Ellipse.OnRender. /// /// This guard scans every XAML file in the app and proves each referenced key exists — /// either in the theme/App resources or in the same file — so the class cannot come back. public class ThemeResourceTests { [Fact] public void Every_StaticResource_reference_resolves_to_a_defined_key() { var root = System.IO.Path.GetDirectoryName(SourceAssert.RepoPath("App.xaml"))!; var globalKeys = new HashSet(StringComparer.Ordinal); foreach (var file in new[] { System.IO.Path.Combine(root, "App.xaml") } .Concat(Directory.GetFiles(System.IO.Path.Combine(root, "Themes"), "*.xaml"))) globalKeys.UnionWith(KeysIn(File.ReadAllText(file))); var missing = new List(); foreach (var path in XamlFiles()) { var text = File.ReadAllText(path); var localKeys = KeysIn(text); foreach (Match match in Regex.Matches(text, @"\{StaticResource ([^}]+)\}")) { var key = match.Groups[1].Value.Trim(); if (key.StartsWith("{", StringComparison.Ordinal)) continue; // nested markup extension if (globalKeys.Contains(key) || localKeys.Contains(key)) continue; missing.Add($"{System.IO.Path.GetFileName(path)}: {key}"); } } Assert.True(missing.Count == 0, "StaticResource keys with no definition (WPF throws UnsetValue at layout):\n " + string.Join("\n ", missing.Distinct())); } private static HashSet KeysIn(string text) => Regex.Matches(text, @"x:Key=""([^""]+)""").Select(m => m.Groups[1].Value) .ToHashSet(StringComparer.Ordinal); private static IEnumerable XamlFiles() { var root = System.IO.Path.GetDirectoryName(SourceAssert.RepoPath("App.xaml"))!; return Directory.EnumerateFiles(root, "*.xaml", SearchOption.AllDirectories) .Where(p => !p.Contains($"{System.IO.Path.DirectorySeparatorChar}obj{System.IO.Path.DirectorySeparatorChar}", StringComparison.Ordinal) && !p.Contains($"{System.IO.Path.DirectorySeparatorChar}bin{System.IO.Path.DirectorySeparatorChar}", StringComparison.Ordinal) && !p.Contains("ytLive.Tests", StringComparison.Ordinal)); } }