fix(vtank): slice 7 fix round C item D3 — bottom-band pin counts implicit widget height
AssertWithinParent only flagged a child crossing a group's bottom edge when that child declared its own h attribute — Number(child, "h") reads 0 for an absent attribute, so an unsized <label>/<field>/<toggle>/ <button> positioned right against a group's bottom edge silently passed even though the retained-UI runtime still gives it a real default row height at draw time. Added EffectiveHeight: falls back to each widget kind's own implicit default when h is absent (label/field 16, toggle 20, button 16 as a defensive floor since real buttons in this markup range 16-25px and always declare h explicitly); <list>/<menu> keep the old "0 when absent" behavior since they have no implicit default at all. Mutation named: temporarily reverted the check back to Number(child, "h") and confirmed the new AssertWithinParent_CatchesAnUnsizedLabelNearTheBottomEdge pin fails (no exception thrown for a synthetic <label y="190"> with no h inside a 194-tall group, which should clip 12px past the bottom once the 16px default is counted) before restoring the fix. Audited every real mosstank*.xml file for label/toggle/field/button elements missing h (grep for each without ` h="`) — none exist, so this stricter check introduces no new failures against the shipped markup. MossTank suite 679 -> 680 (one new pin). Full solution build green; App markup/plugin filter 203/203. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
f15667db5f
commit
3b8d021946
1 changed files with 53 additions and 1 deletions
|
|
@ -331,6 +331,26 @@ public sealed class MossTankMarkupContractTests
|
|||
AssertWithinParent(root);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix round C item D3: direct pin on <see cref="AssertWithinParent"/>'s
|
||||
/// height check, independent of any real markup file. A
|
||||
/// <c><label y="190"></c> with no declared <c>h</c> inside a
|
||||
/// 194-tall group clips 12px past the bottom edge once the label's
|
||||
/// real 16px default row height is counted (190 + 16 = 206 > 194) —
|
||||
/// before this fix, an absent <c>h</c> read as zero height and the
|
||||
/// check silently passed.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AssertWithinParent_CatchesAnUnsizedLabelNearTheBottomEdge()
|
||||
{
|
||||
var group = new XElement("group",
|
||||
new XAttribute("w", "848"), new XAttribute("h", "194"),
|
||||
new XElement("label", new XAttribute("x", "4"), new XAttribute("y", "190"),
|
||||
new XAttribute("text", "Notice")));
|
||||
|
||||
Assert.Throws<Xunit.Sdk.TrueException>(() => AssertWithinParent(group));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix round B item 2: <see cref="AssertWithinParent"/> only ever proved
|
||||
/// a control fits inside its OWN parent's declared bounds — it never
|
||||
|
|
@ -571,7 +591,7 @@ public sealed class MossTankMarkupContractTests
|
|||
foreach (XElement child in parent.Elements())
|
||||
{
|
||||
float width = Number(child, "w");
|
||||
float height = Number(child, "h");
|
||||
float height = EffectiveHeight(child);
|
||||
if (width > 0f)
|
||||
{
|
||||
Assert.True(
|
||||
|
|
@ -588,6 +608,38 @@ public sealed class MossTankMarkupContractTests
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix round C item D3: an element's declared <c>h</c> only tells the
|
||||
/// whole story for widget kinds that never rely on an implicit
|
||||
/// default. <c><label></c>/<c><field></c> without <c>h</c>
|
||||
/// still occupy one DAT-font text row (16px) at runtime, and
|
||||
/// <c><toggle></c> still occupies the checkbox lamp's own 20px
|
||||
/// footprint — <see cref="AssertWithinParent"/> used to treat any of
|
||||
/// those as zero-height (h absent) and silently pass an unsized notice
|
||||
/// label positioned right up against a group's bottom edge, which
|
||||
/// actually clips in the running client. <c><button></c> has no
|
||||
/// single canonical default (real buttons in this markup range from
|
||||
/// 16 to 25px and always declare h explicitly), so 16 — the same
|
||||
/// floor as label/field — is used defensively; <c><list></c>/
|
||||
/// <c><menu></c> have no implicit default at all and keep the
|
||||
/// old "0 when absent" behavior.
|
||||
/// </summary>
|
||||
private static float EffectiveHeight(XElement element)
|
||||
{
|
||||
float declared = Number(element, "h");
|
||||
if (declared > 0f)
|
||||
return declared;
|
||||
|
||||
return element.Name.LocalName switch
|
||||
{
|
||||
"label" => 16f,
|
||||
"field" => 16f,
|
||||
"toggle" => 20f,
|
||||
"button" => 16f,
|
||||
_ => 0f,
|
||||
};
|
||||
}
|
||||
|
||||
private static float Number(XElement element, string attribute) =>
|
||||
float.TryParse(
|
||||
(string?)element.Attribute(attribute),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue