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.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("name")); } [Test] public void Set_Get_Int() { ShrinkSettings.Set("score", 42); Assert.AreEqual(42, ShrinkSettings.Get("score")); } [Test] public void Set_Get_Float() { ShrinkSettings.Set("volume", 0.75f); Assert.AreEqual(0.75f, ShrinkSettings.Get("volume"), 0.001f); } [Test] public void Set_Get_Bool() { ShrinkSettings.Set("muted", true); Assert.IsTrue(ShrinkSettings.Get("muted")); } [Test] public void Set_Get_ComplexObject() { var data = new Dictionary { { "a", 1 }, { "b", 2 } }; ShrinkSettings.Set("map", data); var restored = ShrinkSettings.Get>("map"); Assert.AreEqual(1, restored["a"]); Assert.AreEqual(2, restored["b"]); } [Test] public void Get_NonExistentKey_ReturnsDefault() { Assert.AreEqual(0, ShrinkSettings.Get("missing")); Assert.IsNull(ShrinkSettings.Get("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("persist_str")); Assert.AreEqual(42, ShrinkSettings.Get("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("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("key")); } } }