feat(packages): 内置 SDK 包并完善 ContextLoader 集成
- 将 ShrinkEventBus、ShrinkDataSaver 及其 EventBus 集成从 gitlink 转为仓库直接维护的完整 UPM 包,补齐运行时、编辑器工具、测试与文档 - 新增 Command 和 Network 的 App 集成组件,支持 ContextLoader 服务发布、可逆注销及 Network Loopback 生命周期管理 - 更新 Starter 与演示组合逻辑,缺失模块时可注册、已有兼容安装器时可覆盖,并补充宿主启动断言 - 升级内部包依赖与 Shared CodeGen 包定义,放宽 Integration.App 包的 Git 忽略规则 - 将独立服务器生成器改为基于已编译程序集的语义扫描,支持 partial、复杂泛型、命名冲突检测及模板 SHA-256 覆写保护 - 新增 Network 语义扫描、模板保护和 App 组件生命周期测试 - 新增真实 UPM 消费工程验证脚本,校验内部版本一致性、程序集加载及 EditMode 测试 - 重构当前架构文档并归档已完成的 Cordis 迁移与旧代码地图
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace ShrinkDataSaver.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ShrinkSettingsTests
|
||||
{
|
||||
private MockStorageProvider _storage;
|
||||
private ShrinkDataSaverSettings _settings;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_storage = new MockStorageProvider();
|
||||
_settings = ScriptableObject.CreateInstance<ShrinkDataSaverSettings>();
|
||||
ShrinkDataSaverSettings.Instance = _settings;
|
||||
ShrinkSettings.ResetForTesting();
|
||||
ShrinkSettings.Initialize(_storage, "settings.json");
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
ShrinkSettings.ResetForTesting();
|
||||
if (_settings != null) Object.DestroyImmediate(_settings);
|
||||
}
|
||||
|
||||
// ── Get / Set ──
|
||||
|
||||
[Test]
|
||||
public void Set_Get_String()
|
||||
{
|
||||
ShrinkSettings.Set("name", "Alice");
|
||||
Assert.AreEqual("Alice", ShrinkSettings.Get<string>("name"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Set_Get_Int()
|
||||
{
|
||||
ShrinkSettings.Set("score", 42);
|
||||
Assert.AreEqual(42, ShrinkSettings.Get<int>("score"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Set_Get_Float()
|
||||
{
|
||||
ShrinkSettings.Set("volume", 0.75f);
|
||||
Assert.AreEqual(0.75f, ShrinkSettings.Get<float>("volume"), 0.001f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Set_Get_Bool()
|
||||
{
|
||||
ShrinkSettings.Set("muted", true);
|
||||
Assert.IsTrue(ShrinkSettings.Get<bool>("muted"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Set_Get_ComplexObject()
|
||||
{
|
||||
var data = new Dictionary<string, int> { { "a", 1 }, { "b", 2 } };
|
||||
ShrinkSettings.Set("map", data);
|
||||
var restored = ShrinkSettings.Get<Dictionary<string, int>>("map");
|
||||
|
||||
Assert.AreEqual(1, restored["a"]);
|
||||
Assert.AreEqual(2, restored["b"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_NonExistentKey_ReturnsDefault()
|
||||
{
|
||||
Assert.AreEqual(0, ShrinkSettings.Get<int>("missing"));
|
||||
Assert.IsNull(ShrinkSettings.Get<string>("missing"));
|
||||
Assert.AreEqual(99, ShrinkSettings.Get("missing", 99));
|
||||
}
|
||||
|
||||
// ── Has / Remove ──
|
||||
|
||||
[Test]
|
||||
public void Has_ExistingKey_ReturnsTrue()
|
||||
{
|
||||
ShrinkSettings.Set("key", "value");
|
||||
Assert.IsTrue(ShrinkSettings.Has("key"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Has_NonExistentKey_ReturnsFalse()
|
||||
{
|
||||
Assert.IsFalse(ShrinkSettings.Has("ghost"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Remove_ExistingKey()
|
||||
{
|
||||
ShrinkSettings.Set("temp", 123);
|
||||
Assert.IsTrue(ShrinkSettings.Has("temp"));
|
||||
|
||||
ShrinkSettings.Remove("temp");
|
||||
Assert.IsFalse(ShrinkSettings.Has("temp"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Remove_NonExistentKey_NoError()
|
||||
{
|
||||
Assert.DoesNotThrow(() => ShrinkSettings.Remove("ghost"));
|
||||
}
|
||||
|
||||
// ── GetAllRaw ──
|
||||
|
||||
[Test]
|
||||
public void GetAllRaw_ReturnsAllSettings()
|
||||
{
|
||||
ShrinkSettings.Set("a", 1);
|
||||
ShrinkSettings.Set("b", "two");
|
||||
ShrinkSettings.Set("c", true);
|
||||
|
||||
var all = ShrinkSettings.GetAllRaw();
|
||||
Assert.AreEqual(3, all.Count);
|
||||
Assert.IsTrue(all.ContainsKey("a"));
|
||||
Assert.IsTrue(all.ContainsKey("b"));
|
||||
Assert.IsTrue(all.ContainsKey("c"));
|
||||
}
|
||||
|
||||
// ── 事件 ──
|
||||
|
||||
[Test]
|
||||
public void OnChanged_FiredOnSet()
|
||||
{
|
||||
string receivedKey = null;
|
||||
object receivedValue = null;
|
||||
ShrinkSettings.OnChanged += (k, v) => { receivedKey = k; receivedValue = v; };
|
||||
|
||||
ShrinkSettings.Set("volume", 0.5f);
|
||||
|
||||
Assert.AreEqual("volume", receivedKey);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnChanged_FiredOnRemove()
|
||||
{
|
||||
ShrinkSettings.Set("temp", "data");
|
||||
|
||||
string removedKey = null;
|
||||
ShrinkSettings.OnChanged += (k, v) => { removedKey = k; };
|
||||
|
||||
ShrinkSettings.Remove("temp");
|
||||
Assert.AreEqual("temp", removedKey);
|
||||
}
|
||||
|
||||
// ── 持久化 ──
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SaveAsync_LoadAsync_RoundTrip() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
ShrinkSettings.Set("persist_str", "hello");
|
||||
ShrinkSettings.Set("persist_int", 42);
|
||||
await ShrinkSettings.SaveAsync();
|
||||
|
||||
// 重置内存数据后重新加载
|
||||
ShrinkSettings.ResetForTesting();
|
||||
ShrinkSettings.Initialize(_storage, "settings.json");
|
||||
|
||||
await ShrinkSettings.LoadAsync();
|
||||
|
||||
Assert.AreEqual("hello", ShrinkSettings.Get<string>("persist_str"));
|
||||
Assert.AreEqual(42, ShrinkSettings.Get<int>("persist_int"));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LoadAsync_EmptyStorage_GivesCleanState() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await ShrinkSettings.LoadAsync();
|
||||
Assert.AreEqual(0, ShrinkSettings.GetAllRaw().Count);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LoadAsync_FallsBackToBackup_WhenPrimaryCorrupted() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
ShrinkSettings.Set("lang", "zh_cn");
|
||||
await ShrinkSettings.SaveAsync();
|
||||
|
||||
var backupBytes = await _storage.ReadAsync("settings.json");
|
||||
await _storage.WriteAsync("settings.json.bak1", backupBytes);
|
||||
// 用无法解析的字节模拟主文件损坏:结构合法但字段不符的 JSON 无法与“合法空设置”区分
|
||||
await _storage.WriteAsync("settings.json", System.Text.Encoding.UTF8.GetBytes("{ \"lang\": \"zh_cn\" , broken"));
|
||||
|
||||
ShrinkSettings.ResetForTesting();
|
||||
ShrinkSettings.Initialize(_storage, "settings.json");
|
||||
|
||||
await ShrinkSettings.LoadAsync();
|
||||
|
||||
Assert.AreEqual("zh_cn", ShrinkSettings.Get<string>("lang"));
|
||||
var repairedPrimary = await _storage.ReadAsync("settings.json");
|
||||
CollectionAssert.AreEqual(backupBytes, repairedPrimary);
|
||||
});
|
||||
|
||||
// ── Overwrite ──
|
||||
|
||||
[Test]
|
||||
public void Set_OverwriteExistingKey()
|
||||
{
|
||||
ShrinkSettings.Set("key", "first");
|
||||
ShrinkSettings.Set("key", "second");
|
||||
Assert.AreEqual("second", ShrinkSettings.Get<string>("key"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user