test(vt): round 3 item 8 — nav byte-identity coverage + s-cell strip + .ast round-trip
The already-committed nav_briennecarlus.af/nav_empyrean.af/nav_lockandkeyjaw.af
fixtures (checkpoint/recall/portal2 node coverage, clean metaf headers)
were exercised by the model-equality proofs (parse, parse-write-parse,
binary-import-matches-af) but never by the REAL byte-identical writer-output
theory, which only ever covered nav_ab.af. Converted
WriterOutputMatchesMetafCanonicalEmissionNavOnly into a Theory over all
four nav-only fixtures.
Added two more coverage gaps this round's audit named:
- StringCellStripsEmbeddedNewlineAtConstructionNotJustOnWrite pins
VtankCell.String's gy.cs:84 newline strip (construction-time, not just
at WriteTo).
- RealAstFixturesRoundTripByteIdentical extends the existing schema-only
owner-{a,b,c}.ast coverage to a real parse -> Render() byte-identity
round trip, the same proof-4 rigor MetafSerializerTests already applies
to .af fixtures.
No writer bug surfaced in the extended nav theory or the .ast round trip —
both already passed; these are coverage-closing additions, not fixes.
Verified each new test has teeth via a temporary synthetic mutation rather
than a real revert (there is no production fix to revert here): the
string-cell test was checked against a temporarily-unstripped VtankCell.String
(failed, restored), and the .ast round-trip was checked against a
temporarily LF-only VtankWriter.AppendLine (all three .ast cases failed,
the four nav cases were unaffected since MetafSerializer's .af writer is a
separate code path from VtankUsdDocument's "y" grammar writer — restored).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
d98bf4a139
commit
2566dad1d3
3 changed files with 66 additions and 5 deletions
|
|
@ -234,12 +234,30 @@ public sealed class MetafSerializerTests
|
|||
|
||||
// Proof (4), nav-only case: SaveNav's own header (navHeader) and
|
||||
// single-Nav fold-marker wrap are byte-identical to a real nav-only
|
||||
// .af fixture. nav_ab.af's header is metaf's own fresh banner (first
|
||||
// bytes "~~ {\n~~ ", matching every clean meta fixture above).
|
||||
[Fact]
|
||||
public void WriterOutputMatchesMetafCanonicalEmissionNavOnly()
|
||||
// .af fixture. Every listed fixture carries metaf's own fresh banner
|
||||
// (first bytes "~~ {\n~~ "); round 3 item 8 extended this from a
|
||||
// single fixture (nav_ab.af) to the three checkpoint/recall/portal2
|
||||
// fixtures copied from the metas repo (nav_briennecarlus.af carries
|
||||
// chk+jmp, nav_empyrean.af carries rcl+ptl, nav_lockandkeyjaw.af
|
||||
// carries rcl+chk) so the theory actually exercises every node kind
|
||||
// metaf's own grammar supports, not just plain point waypoints.
|
||||
public static TheoryData<string> NavByteIdenticalFixtureData()
|
||||
{
|
||||
var data = new TheoryData<string>();
|
||||
foreach (string name in new[]
|
||||
{
|
||||
"nav_ab", "nav_briennecarlus", "nav_empyrean", "nav_lockandkeyjaw",
|
||||
})
|
||||
{
|
||||
data.Add(Path.Combine(FixturesRoot, "af", name + ".af"));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(NavByteIdenticalFixtureData))]
|
||||
public void WriterOutputMatchesMetafCanonicalEmissionNavOnly(string path)
|
||||
{
|
||||
string path = Path.Combine(FixturesRoot, "af", "nav_ab.af");
|
||||
string original = File.ReadAllText(path);
|
||||
var settings = new NavigationSettings();
|
||||
Assert.True(
|
||||
|
|
|
|||
|
|
@ -324,6 +324,28 @@ public sealed class VtankProfileDirectoryTests
|
|||
spells!.ColumnNames);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round 3 item 8: the shared "y" database grammar's writer must be
|
||||
/// REAL byte-identical against real installed data, not just the
|
||||
/// hand-built synthetic fixtures in VtankUsdDocumentTests — the three
|
||||
/// real owner-*.ast per-character spell-tracking caches round-trip
|
||||
/// through parse -> Render() unchanged.
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData("owner-a.ast")]
|
||||
[InlineData("owner-b.ast")]
|
||||
[InlineData("owner-c.ast")]
|
||||
public void RealAstFixturesRoundTripByteIdentical(string fileName)
|
||||
{
|
||||
string original = File.ReadAllText(
|
||||
Path.Combine(AppContext.BaseDirectory, "Fixtures", "vtank", fileName));
|
||||
|
||||
VtankDatabase database = VtankDatabase.Parse(original);
|
||||
string rewritten = database.Render();
|
||||
|
||||
Assert.Equal(original, rewritten);
|
||||
}
|
||||
|
||||
private sealed class MemoryStorage : IPluginStorage
|
||||
{
|
||||
private readonly Dictionary<string, string> _text = new(StringComparer.Ordinal);
|
||||
|
|
|
|||
|
|
@ -110,4 +110,25 @@ public sealed class VtankUsdDocumentTests
|
|||
["Apple", "Mango", "Zebra"],
|
||||
reparsed.Tables.Select(static entry => entry.Name).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round 3 item 8: pins <c>VtankCell.String</c>'s embedded-newline strip
|
||||
/// (<c>gy.cs:84</c>: <c>text.Replace("\n", "")</c> — VTank's own writer
|
||||
/// never emits a multi-line "s" cell; only a <c>ba</c> blob can carry
|
||||
/// embedded newlines, see <see cref="BaBlobWithEmbeddedCrlfRoundTripsExactCharacterCount"/>).
|
||||
/// The strip happens at construction, not only at write time, so a
|
||||
/// caller reading the cell back via <see cref="VtankCell.AsString"/>
|
||||
/// never sees the stripped character either.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void StringCellStripsEmbeddedNewlineAtConstructionNotJustOnWrite()
|
||||
{
|
||||
VtankCell cell = VtankCell.String("line1\nline2");
|
||||
|
||||
Assert.Equal("line1line2", cell.AsString());
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
cell.WriteTo(sb);
|
||||
Assert.Equal("s\r\nline1line2\r\n", sb.ToString());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue