test(save): 添加开发存档清单校验测试
This commit is contained in:
@@ -7,6 +7,7 @@ using System.Text;
|
||||
using AibisDream.SaveSystem;
|
||||
using AibisDream.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
@@ -374,5 +375,139 @@ namespace AibisDream.EditorTools
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public sealed class DevSaveCatalogTests
|
||||
{
|
||||
private string root;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
root = Path.Combine(Path.GetTempPath(), $"aibis-dev-save-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(root);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (Directory.Exists(root)) Directory.Delete(root, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CatalogUsesExplicitOrderAndKeepsInvalidEntriesVisible()
|
||||
{
|
||||
WriteCatalog(new DevSaveCatalogEntryDto { order = 20, label = "late", path = "S/late", anchorNode = "Late" },
|
||||
new DevSaveCatalogEntryDto { order = 10, label = "early", path = "S/early", anchorNode = "Early" });
|
||||
|
||||
var section = DevSaveCatalog.Load(root).Single();
|
||||
|
||||
Assert.That(section.Entries.Select(entry => entry.Label), Is.EqualTo(new[] { "early", "late" }));
|
||||
Assert.That(section.Entries.All(entry => !entry.IsValid), Is.True);
|
||||
Assert.That(section.Entries.All(entry => entry.Error.Contains("缺失")), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CatalogRejectsPathTraversal()
|
||||
{
|
||||
WriteCatalog(new DevSaveCatalogEntryDto { order = 1, label = "unsafe", path = "../outside", anchorNode = "Start" });
|
||||
|
||||
var entry = DevSaveCatalog.Load(root).Single().Entries.Single();
|
||||
|
||||
Assert.That(entry.IsValid, Is.False);
|
||||
Assert.That(entry.Error, Does.Contain("越过"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CatalogReportsCorruptSchemaAndAnchorMismatch()
|
||||
{
|
||||
WriteSnapshot("S/corrupt", "{");
|
||||
WriteSnapshot("S/schema", JsonConvert.SerializeObject(BuildSnapshot("Node", schema: 99)));
|
||||
WriteSnapshot("S/node", JsonConvert.SerializeObject(BuildSnapshot("Actual")));
|
||||
WriteCatalog(
|
||||
new DevSaveCatalogEntryDto { order = 1, label = "corrupt", path = "S/corrupt", anchorNode = "Node" },
|
||||
new DevSaveCatalogEntryDto { order = 2, label = "schema", path = "S/schema", anchorNode = "Node" },
|
||||
new DevSaveCatalogEntryDto { order = 3, label = "node", path = "S/node", anchorNode = "Expected" });
|
||||
|
||||
var entries = DevSaveCatalog.Load(root).Single().Entries;
|
||||
|
||||
Assert.That(entries[0].Error, Does.Contain("JSON"));
|
||||
Assert.That(entries[1].Error, Does.Contain("版本"));
|
||||
Assert.That(entries[2].Error, Does.Contain("节点不匹配"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CommittedCatalogContainsOnlyValidUniqueEntries()
|
||||
{
|
||||
var sections = DevSaveCatalog.Load(ConstRef.TestSaveFilePath);
|
||||
Assert.That(DevSaveCatalog.LastError, Is.Null);
|
||||
Assert.That(sections.Count, Is.GreaterThan(0));
|
||||
foreach (var section in sections)
|
||||
{
|
||||
Assert.That(section.Entries, Is.Not.Empty, section.Id);
|
||||
Assert.That(section.Entries.All(entry => entry.IsValid), Is.True,
|
||||
string.Join("\n", section.Entries.Where(entry => !entry.IsValid).Select(entry => $"{entry.Label}: {entry.Error}")));
|
||||
Assert.That(section.Entries.Select(entry => entry.Order).Distinct().Count(), Is.EqualTo(section.Entries.Count));
|
||||
Assert.That(section.Entries.Select(entry => entry.AnchorNode).Distinct().Count(), Is.EqualTo(section.Entries.Count));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StrictRestoreContextTracksPhaseWarningsAndErrors()
|
||||
{
|
||||
var context = new SnapshotRestoreContext(new SaveSnapshot(), strictMode: true);
|
||||
context.SetPhase("Provider restore");
|
||||
context.Warn("optional state missing");
|
||||
context.Error("required state missing");
|
||||
|
||||
Assert.That(context.StrictMode, Is.True);
|
||||
Assert.That(context.CurrentPhase, Is.EqualTo("Provider restore"));
|
||||
Assert.That(context.Warnings, Is.EqualTo(new[] { "optional state missing" }));
|
||||
Assert.That(context.Errors, Is.EqualTo(new[] { "required state missing" }));
|
||||
Assert.That(context.HasErrors, Is.True);
|
||||
}
|
||||
|
||||
private void WriteCatalog(params DevSaveCatalogEntryDto[] entries)
|
||||
{
|
||||
var catalog = new DevSaveCatalogDto
|
||||
{
|
||||
sections = new List<DevSaveCatalogSectionDto>
|
||||
{
|
||||
new()
|
||||
{
|
||||
id = "S",
|
||||
title = "Section",
|
||||
expectedSceneName = "Scene/Test",
|
||||
expectedSceneSoName = "TestSO",
|
||||
expectedYarnProjectId = "TestYarn",
|
||||
entries = entries.ToList()
|
||||
}
|
||||
}
|
||||
};
|
||||
File.WriteAllText(Path.Combine(root, "catalog.json"), JsonConvert.SerializeObject(catalog));
|
||||
}
|
||||
|
||||
private void WriteSnapshot(string relativeDirectory, string json)
|
||||
{
|
||||
var directory = Path.Combine(root, relativeDirectory.Replace('/', Path.DirectorySeparatorChar));
|
||||
Directory.CreateDirectory(directory);
|
||||
File.WriteAllText(Path.Combine(directory, "snapshot.json"), json);
|
||||
}
|
||||
|
||||
private static SaveSnapshot BuildSnapshot(string node, int schema = SaveSnapshotSchema.CurrentVersion)
|
||||
{
|
||||
return new SaveSnapshot
|
||||
{
|
||||
schemaVersion = schema,
|
||||
scene = new SceneSnapshotDto { sceneName = "Scene/Test" },
|
||||
anchor = new AnchorSnapshot
|
||||
{
|
||||
sceneSoName = "TestSO",
|
||||
yarnProjectId = "TestYarn",
|
||||
nodeName = node
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user