diff --git a/HANDOFF.md b/HANDOFF.md index 7e5d3b3..98517ad 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -6,19 +6,21 @@ - `ChannelStatsServiceTests` uses dates relative to UTC so its 90-day upload assertion does not expire with the calendar; fix committed as `3985a41`. - `ScoreboardPropertiesTests` now checks for the themed `PropertyPillCheck` style instead of stale - `YtCheckBox` markup; focused test passes. This task is ready to commit. -- Clean app build is 0 warnings. Full suite: 11 failed / 511 passed of 522; remaining failures are + `YtCheckBox` markup; committed as `221b816`. +- `PropertiesHierarchyTests` now checks shared styles and scopes the duplicate shape bindings to + the Shape block; focused test passes. This task is ready to commit. +- Clean app build is 0 warnings. Full suite: 10 failed / 512 passed of 522; remaining failures are being handled one task and one local commit at a time. ## Next action -Commit the scoreboard-properties assertion update, then take the next remaining failure. Do not +Commit the properties-hierarchy assertion update, then take the next remaining failure. Do not push absent a milestone/checkpoint request. ## Landmines - Build/test with Windows `dotnet.exe`; the full suite can hang in WASAPI teardown. -- `verify.sh` cannot pass until the remaining 11 suite failures are resolved; scope checks are run +- `verify.sh` cannot pass until the remaining 10 suite failures are resolved; scope checks are run separately when that gate exits early. - Any integration test constructing `MainWindow` must set `LayoutPathOverride` to a temporary DB and clear it in `finally`. diff --git a/ytLive.Tests/PropertiesHierarchyTests.cs b/ytLive.Tests/PropertiesHierarchyTests.cs index 73612a2..843aeb3 100644 --- a/ytLive.Tests/PropertiesHierarchyTests.cs +++ b/ytLive.Tests/PropertiesHierarchyTests.cs @@ -47,20 +47,27 @@ public class PropertiesHierarchyTests // ── The panel: a Shape title owns the options, the hint is indented ─── var doc = XDocument.Load(SourceAssert.RepoPath("Controls", "LeftPanel.xaml")); + XNamespace xaml = "http://schemas.microsoft.com/winfx/2006/xaml"; + var theme = XDocument.Load(SourceAssert.RepoPath("Themes", "Controls.xaml")); + var propertyHeaderStyle = theme.Descendants().Single(e => e.Name.LocalName == "Style" + && (string?)e.Attribute(xaml + "Key") == "PropertyHeader"); + var fontWeight = propertyHeaderStyle.Elements().Single(e => e.Name.LocalName == "Setter" + && (string?)e.Attribute("Property") == "FontWeight"); + Assert.Equal("SemiBold", (string?)fontWeight.Attribute("Value")); var shapeTitle = doc.Descendants().Single(e => e.Name.LocalName == "TextBlock" && (string?)e.Attribute("Text") == "Shape"); - Assert.Equal("SemiBold", (string?)shapeTitle.Attribute("FontWeight")); + Assert.Equal("{StaticResource PropertyHeader}", (string?)shapeTitle.Attribute("Style")); - var rectOption = OptionBoundTo(doc, "IsRectShape"); - var circleOption = OptionBoundTo(doc, "IsRoundShape"); + var shapeBlock = shapeTitle.Parent!; + var rectOption = OptionBoundTo(shapeBlock, "IsRectShape"); + var circleOption = OptionBoundTo(shapeBlock, "IsRoundShape"); Assert.Contains("TwoWay", (string?)rectOption.Attribute("IsChecked") ?? ""); // The CIRCLE is the option that is not offered in the vertical Chat layout. Assert.Contains("CanToggleClipShape", (string?)circleOption.Attribute("Visibility") ?? ""); // Both options live under the Shape title. - var shapeBlock = shapeTitle.Parent!; Assert.Contains(rectOption, shapeBlock.Descendants()); Assert.Contains(circleOption, shapeBlock.Descendants()); @@ -76,8 +83,8 @@ public class PropertiesHierarchyTests // ── Every titled block owns its content one indent deeper ──────────── var geometryTitle = doc.Descendants() .Where(e => e.Name.LocalName == "TextBlock" && (string?)e.Attribute("Text") == "Geometry") - .Single(e => ((string?)e.Parent?.Attribute("Visibility") ?? "").Contains("IsWebcamSelected")); - Assert.Equal("SemiBold", (string?)geometryTitle.Attribute("FontWeight")); + .Single(e => ((string?)e.Parent?.Attribute("Visibility") ?? "").Contains("SelectedElement.IsDraggable")); + Assert.Equal("{StaticResource PropertyHeader}", (string?)geometryTitle.Attribute("Style")); foreach (var row in geometryTitle.Parent!.Elements().Where(e => e.Name.LocalName == "DockPanel")) Assert.Equal(10, LeftIndent(row)); @@ -89,7 +96,7 @@ public class PropertiesHierarchyTests { var label = webcamPanel.Descendants().Single(e => e.Name.LocalName == "TextBlock" && (string?)e.Attribute("Text") == title); - Assert.Equal("SemiBold", (string?)label.Attribute("FontWeight")); + Assert.Equal("{StaticResource PropertyHeader}", (string?)label.Attribute("Style")); Assert.Equal(10, LeftIndent(RowAfter(label))); } @@ -101,8 +108,8 @@ public class PropertiesHierarchyTests } /// The shape option bound to the given model property. - private static XElement OptionBoundTo(XDocument doc, string property) => - doc.Descendants().Single(e => e.Name.LocalName == "ToggleButton" + private static XElement OptionBoundTo(XElement scope, string property) => + scope.Descendants().Single(e => e.Name.LocalName == "ToggleButton" && ((string?)e.Attribute("IsChecked") ?? "").Contains(property)); /// The row (DockPanel) that holds the given label.