diff --git a/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs b/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs index 676aa1396..8ba153b50 100644 --- a/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs +++ b/src/AcDream.Plugins.MossTank/MossTankMetaProfileStore.cs @@ -195,7 +195,12 @@ internal sealed class MossTankMetaProfileStore /// .af is the only VTank-compatible export format now (Campaign /// VT slice 1 Part A — MossTank no longer authors the binary /// .met format at all, matching 's - /// demotion to a one-shot import). + /// demotion to a one-shot import). Exports live under + /// exports/meta/ — a distinct subdirectory from + /// 's exports/nav/ — so a + /// Meta profile and a route (Navigation) profile sharing the same name + /// cannot silently overwrite each other's .af file (both stores + /// used to write into the same flat exports/ root). /// 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) diff --git a/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs b/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs index d6af35d8a..49c4ae7af 100644 --- a/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs +++ b/src/AcDream.Plugins.MossTank/MossTankRouteProfileStore.cs @@ -264,7 +264,12 @@ internal sealed class MossTankRouteProfileStore /// .af is the only VTank-compatible export format now (Campaign /// VT slice 1 Part A — MossTank no longer authors the binary /// .nav format at all, matching 's - /// demotion to a one-shot import). + /// demotion to a one-shot import). Exports live under + /// exports/nav/ — a distinct subdirectory from + /// 's exports/meta/ — so a + /// route (Navigation) profile and a Meta profile sharing the same name + /// cannot silently overwrite each other's .af file (both stores + /// used to write into the same flat exports/ root). /// 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) diff --git a/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs b/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs index 2fab57bd8..8a506f9b5 100644 --- a/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs +++ b/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs @@ -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);