fix(vt): C separate exports/meta/ and exports/nav/ .af directories
Item C (slice-1 fix round). MossTankMetaProfileStore and
MossTankRouteProfileStore both wrote their .af exports into the same
flat "exports/" directory keyed only by profile name — a Meta profile
and a route (Navigation) profile sharing a name (e.g. both named
"Same") would silently clobber each other's .af file on save, with no
error and no warning.
- MossTankMetaProfileStore.WriteLegacyExport now writes to
"exports/meta/{name}.af".
- MossTankRouteProfileStore.WriteLegacyExport now writes to
"exports/nav/{name}.af".
- Both class docs updated to name the collision this avoids and point at
the sibling store's subdirectory.
- MossTankPanelTests: existing NavCommandsImportAndExportExactVtankNavFiles
and MetaCommandsImportAndExportExactVtankMetFiles updated to the new
paths. New MetaAndRouteExportsWithTheSameNameDoNotCollide saves a Meta
and a route profile both named "Same" and asserts both .af files exist
with their own correct content — verified failing before the fix
(asserted false on the meta file's existence once both paths were
reverted to the flat "exports/" root, confirming the collision is real
and this test catches it).
Full MossTank suite: 569/569 passing (568 -> 569, one new test).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
e5bc5c6a3f
commit
d0247dbb19
3 changed files with 49 additions and 7 deletions
|
|
@ -195,7 +195,12 @@ internal sealed class MossTankMetaProfileStore
|
|||
/// <c>.af</c> is the only VTank-compatible export format now (Campaign
|
||||
/// VT slice 1 Part A — MossTank no longer authors the binary
|
||||
/// <c>.met</c> format at all, matching <see cref="VtankMetaProfileSerializer"/>'s
|
||||
/// demotion to a one-shot import).
|
||||
/// demotion to a one-shot import). Exports live under
|
||||
/// <c>exports/meta/</c> — a distinct subdirectory from
|
||||
/// <see cref="MossTankRouteProfileStore"/>'s <c>exports/nav/</c> — so a
|
||||
/// Meta profile and a route (Navigation) profile sharing the same name
|
||||
/// cannot silently overwrite each other's <c>.af</c> file (both stores
|
||||
/// used to write into the same flat <c>exports/</c> root).
|
||||
/// </summary>
|
||||
private void WriteLegacyExport(string name, MetaProfile profile)
|
||||
{
|
||||
|
|
@ -204,7 +209,7 @@ internal sealed class MossTankMetaProfileStore
|
|||
try
|
||||
{
|
||||
_host.Storage.WriteText(
|
||||
$"exports/{LegacyFileName(name)}.af",
|
||||
$"exports/meta/{LegacyFileName(name)}.af",
|
||||
MetafSerializer.SaveMeta(profile));
|
||||
}
|
||||
catch (Exception error)
|
||||
|
|
|
|||
|
|
@ -264,7 +264,12 @@ internal sealed class MossTankRouteProfileStore
|
|||
/// <c>.af</c> is the only VTank-compatible export format now (Campaign
|
||||
/// VT slice 1 Part A — MossTank no longer authors the binary
|
||||
/// <c>.nav</c> format at all, matching <see cref="VtankNavRouteSerializer"/>'s
|
||||
/// demotion to a one-shot import).
|
||||
/// demotion to a one-shot import). Exports live under
|
||||
/// <c>exports/nav/</c> — a distinct subdirectory from
|
||||
/// <see cref="MossTankMetaProfileStore"/>'s <c>exports/meta/</c> — so a
|
||||
/// route (Navigation) profile and a Meta profile sharing the same name
|
||||
/// cannot silently overwrite each other's <c>.af</c> file (both stores
|
||||
/// used to write into the same flat <c>exports/</c> root).
|
||||
/// </summary>
|
||||
private void WriteLegacyExport(string name, NavigationSettings settings)
|
||||
{
|
||||
|
|
@ -273,7 +278,7 @@ internal sealed class MossTankRouteProfileStore
|
|||
try
|
||||
{
|
||||
_host.Storage.WriteText(
|
||||
$"exports/{LegacyFileName(name)}.af",
|
||||
$"exports/nav/{LegacyFileName(name)}.af",
|
||||
MetafSerializer.SaveNav(settings));
|
||||
}
|
||||
catch (Exception error)
|
||||
|
|
|
|||
|
|
@ -678,7 +678,39 @@ public sealed class MossTankPanelTests
|
|||
Command(panel, "nav save Exported.nav");
|
||||
Assert.StartsWith(
|
||||
"NAV: ",
|
||||
storage.Text["exports/Exported.af"],
|
||||
storage.Text["exports/nav/Exported.af"],
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
// Item C (Campaign VT slice-1 fix round): a Meta profile and a route
|
||||
// (Navigation) profile named identically used to write into the SAME
|
||||
// flat "exports/" directory — "Same.af" from one silently clobbered
|
||||
// "Same.af" from the other. exports/meta/ and exports/nav/ are
|
||||
// separate subdirectories so both coexist.
|
||||
[Fact]
|
||||
public void MetaAndRouteExportsWithTheSameNameDoNotCollide()
|
||||
{
|
||||
var storage = new MemoryStorage();
|
||||
storage.Text["imports/Same.met"] =
|
||||
"1\r\nCondAct\r\n5\r\nCType\r\nAType\r\nCData\r\nAData\r\nState\r\n"
|
||||
+ "n\r\nn\r\nn\r\nn\r\nn\r\n1\r\n"
|
||||
+ "i\r\n1\r\ni\r\n2\r\ni\r\n0\r\ns\r\n/say imported\r\n"
|
||||
+ "s\r\nDefault\r\n";
|
||||
var panel = new MossTankPanel(new FakeHost(new FakeAutomation(), storage));
|
||||
|
||||
Command(panel, "meta load Same.met");
|
||||
Command(panel, "meta save Same.met");
|
||||
Command(panel, "nav save Same.nav");
|
||||
|
||||
Assert.True(storage.Text.ContainsKey("exports/meta/Same.af"));
|
||||
Assert.True(storage.Text.ContainsKey("exports/nav/Same.af"));
|
||||
Assert.StartsWith(
|
||||
"STATE: ",
|
||||
storage.Text["exports/meta/Same.af"],
|
||||
StringComparison.Ordinal);
|
||||
Assert.StartsWith(
|
||||
"NAV: ",
|
||||
storage.Text["exports/nav/Same.af"],
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
|
|
@ -712,10 +744,10 @@ public sealed class MossTankPanelTests
|
|||
Command(panel, "meta save Exported.met");
|
||||
Assert.StartsWith(
|
||||
"STATE: ",
|
||||
storage.Text["exports/Exported.af"],
|
||||
storage.Text["exports/meta/Exported.af"],
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(MetafSerializer.TryLoadMeta(
|
||||
storage.Text["exports/Exported.af"],
|
||||
storage.Text["exports/meta/Exported.af"],
|
||||
NoOpSpellCatalogForExport.Instance,
|
||||
out MetaProfile exported,
|
||||
out string error), error);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue