diff --git a/tests/AcDream.Plugins.MossTank.Tests/MetafSerializerTests.cs b/tests/AcDream.Plugins.MossTank.Tests/MetafSerializerTests.cs index 8e31beb41..989f76ec9 100644 --- a/tests/AcDream.Plugins.MossTank.Tests/MetafSerializerTests.cs +++ b/tests/AcDream.Plugins.MossTank.Tests/MetafSerializerTests.cs @@ -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 NavByteIdenticalFixtureData() + { + var data = new TheoryData(); + 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( diff --git a/tests/AcDream.Plugins.MossTank.Tests/VtankProfileDirectoryTests.cs b/tests/AcDream.Plugins.MossTank.Tests/VtankProfileDirectoryTests.cs index 76862fabe..c2cac139d 100644 --- a/tests/AcDream.Plugins.MossTank.Tests/VtankProfileDirectoryTests.cs +++ b/tests/AcDream.Plugins.MossTank.Tests/VtankProfileDirectoryTests.cs @@ -324,6 +324,28 @@ public sealed class VtankProfileDirectoryTests spells!.ColumnNames); } + /// + /// 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. + /// + [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 _text = new(StringComparer.Ordinal); diff --git a/tests/AcDream.Plugins.MossTank.Tests/VtankUsdDocumentTests.cs b/tests/AcDream.Plugins.MossTank.Tests/VtankUsdDocumentTests.cs index 90279bf58..191944690 100644 --- a/tests/AcDream.Plugins.MossTank.Tests/VtankUsdDocumentTests.cs +++ b/tests/AcDream.Plugins.MossTank.Tests/VtankUsdDocumentTests.cs @@ -110,4 +110,25 @@ public sealed class VtankUsdDocumentTests ["Apple", "Mango", "Zebra"], reparsed.Tables.Select(static entry => entry.Name).ToArray()); } + + /// + /// Round 3 item 8: pins VtankCell.String's embedded-newline strip + /// (gy.cs:84: text.Replace("\n", "") — VTank's own writer + /// never emits a multi-line "s" cell; only a ba blob can carry + /// embedded newlines, see ). + /// The strip happens at construction, not only at write time, so a + /// caller reading the cell back via + /// never sees the stripped character either. + /// + [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()); + } }