feat: update Godot integration and coordinated package dependencies
This commit is contained in:
11 files changed
+525
-49
No files matched your search
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace ShrinkDataSaver.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class LocalStorageProviderStrategyTests
|
||||
{
|
||||
private string _rootPath;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_rootPath = Path.Combine(Path.GetTempPath(), $"ShrinkDataSaverStrategyTests_{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(_rootPath);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (Directory.Exists(_rootPath))
|
||||
{
|
||||
Directory.Delete(_rootPath, true);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultConstructor_UsesFileReplace()
|
||||
{
|
||||
Assert.AreEqual(LocalStorageCommitStrategy.FileReplace,
|
||||
new LocalStorageProvider(_rootPath).CommitStrategy);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RenameOnly_RotatesTwoBackups() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
await WriteAsync(provider, "one");
|
||||
await WriteAsync(provider, "two");
|
||||
await WriteAsync(provider, "three");
|
||||
|
||||
Assert.AreEqual("three", await ReadAsync(provider, "save.dat"));
|
||||
Assert.AreEqual("two", await ReadAsync(provider, "save.dat.bak1"));
|
||||
Assert.AreEqual("one", await ReadAsync(provider, "save.dat.bak2"));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RenameOnly_RecoversPrimaryFromBak1_WhenPrimaryMissing() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
await WriteAsync(provider, "one");
|
||||
await WriteAsync(provider, "two");
|
||||
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
var primaryBackup = primary + ".bak1";
|
||||
File.Delete(primaryBackup);
|
||||
File.Move(primary, primaryBackup);
|
||||
|
||||
Assert.IsTrue(await provider.ExistsAsync("save.dat"));
|
||||
Assert.AreEqual("two", await ReadAsync(provider, "save.dat"));
|
||||
Assert.IsTrue(File.Exists(primary));
|
||||
Assert.IsFalse(File.Exists(primaryBackup));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RenameOnly_RecoversPrimaryFromBak2_WhenBak1Missing() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
await WriteAsync(provider, "one");
|
||||
await WriteAsync(provider, "two");
|
||||
await WriteAsync(provider, "three");
|
||||
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
File.Delete(primary);
|
||||
File.Delete(primary + ".bak1");
|
||||
|
||||
Assert.AreEqual("one", await ReadAsync(provider, "save.dat"));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RenameOnly_DeletesStaleTempBeforeWrite() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
await WriteAsync(provider, "one");
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
File.WriteAllText(primary + ".tmp", "stale", Encoding.UTF8);
|
||||
|
||||
await WriteAsync(provider, "two");
|
||||
|
||||
Assert.IsFalse(File.Exists(primary + ".tmp"));
|
||||
Assert.AreEqual("two", await ReadAsync(provider, "save.dat"));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RenameOnly_PreservesSecondGeneration_WhenBak1Missing() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
await WriteAsync(provider, "one");
|
||||
await WriteAsync(provider, "two");
|
||||
await WriteAsync(provider, "three");
|
||||
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
File.Delete(primary + ".bak1");
|
||||
|
||||
await WriteAsync(provider, "four");
|
||||
|
||||
Assert.AreEqual("four", await ReadAsync(provider, "save.dat"));
|
||||
Assert.AreEqual("three", await ReadAsync(provider, "save.dat.bak1"));
|
||||
Assert.AreEqual("one", await ReadAsync(provider, "save.dat.bak2"));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RenameOnly_DoesNotPromoteOrphanTemp() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
File.WriteAllText(primary + ".tmp", "partial", new UTF8Encoding(false));
|
||||
|
||||
Assert.IsFalse(await provider.ExistsAsync("save.dat"));
|
||||
Assert.IsFalse(File.Exists(primary));
|
||||
Assert.IsFalse(File.Exists(primary + ".tmp"));
|
||||
|
||||
var readFailed = false;
|
||||
try
|
||||
{
|
||||
await ReadAsync(provider, "save.dat");
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
readFailed = true;
|
||||
}
|
||||
|
||||
Assert.IsTrue(readFailed);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator RenameOnly_PrefersBackupOverPartialTemp() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
await WriteAsync(provider, "one");
|
||||
await WriteAsync(provider, "two");
|
||||
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
File.Delete(primary);
|
||||
File.WriteAllText(primary + ".tmp", "partial", new UTF8Encoding(false));
|
||||
|
||||
Assert.IsTrue(await provider.ExistsAsync("save.dat"));
|
||||
Assert.AreEqual("one", await ReadAsync(provider, "save.dat"));
|
||||
Assert.IsFalse(File.Exists(primary + ".tmp"));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator FileReplace_DoesNotApplyRenameOnlyRecovery() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath);
|
||||
await WriteAsync(provider, "one");
|
||||
await WriteAsync(provider, "two");
|
||||
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
File.Delete(primary);
|
||||
File.WriteAllText(primary + ".tmp", "partial", new UTF8Encoding(false));
|
||||
|
||||
Assert.IsFalse(await provider.ExistsAsync("save.dat"));
|
||||
Assert.IsTrue(File.Exists(primary + ".bak1"));
|
||||
Assert.IsTrue(File.Exists(primary + ".tmp"));
|
||||
|
||||
var readFailed = false;
|
||||
try
|
||||
{
|
||||
await ReadAsync(provider, "save.dat");
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
readFailed = true;
|
||||
}
|
||||
|
||||
Assert.IsTrue(readFailed);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DeleteAsync_RemovesBackupsAndTemp() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var provider = new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly, TestMove);
|
||||
await WriteAsync(provider, "one");
|
||||
await WriteAsync(provider, "two");
|
||||
var primary = Path.Combine(_rootPath, "save.dat");
|
||||
File.WriteAllText(primary + ".tmp", "stale", Encoding.UTF8);
|
||||
|
||||
await provider.DeleteAsync("save.dat");
|
||||
|
||||
Assert.IsFalse(File.Exists(primary));
|
||||
Assert.IsFalse(File.Exists(primary + ".bak1"));
|
||||
Assert.IsFalse(File.Exists(primary + ".bak2"));
|
||||
Assert.IsFalse(File.Exists(primary + ".tmp"));
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator PlatformInitialize_UsesInjectedStorage() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var storage = new MockStorageProvider();
|
||||
ShrinkSettings.ResetForTesting();
|
||||
ShrinkDataSaverPlatform.Initialize(storage, "runtime-root");
|
||||
ShrinkSettings.Set("injected", 7);
|
||||
await ShrinkSettings.SaveAsync();
|
||||
|
||||
Assert.IsTrue(await storage.ExistsAsync("runtime-root/settings.json"));
|
||||
var bytes = await storage.ReadAsync("runtime-root/settings.json");
|
||||
StringAssert.Contains("\"injected\"", Encoding.UTF8.GetString(bytes));
|
||||
});
|
||||
|
||||
// Tests the shared rotation contract; Godot integration tests exercise actual overwrite rename.
|
||||
private static void TestMove(string source, string destination)
|
||||
{
|
||||
if (File.Exists(destination)) File.Delete(destination);
|
||||
File.Move(source, destination);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenameOnly_RequiresOverwriteCapability() => Assert.Throws<ArgumentException>(() =>
|
||||
new LocalStorageProvider(_rootPath, LocalStorageCommitStrategy.RenameOnly));
|
||||
|
||||
private static async UniTask WriteAsync(IStorageProvider provider, string value)
|
||||
{
|
||||
await provider.WriteAsync("save.dat", Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
private static async UniTask<string> ReadAsync(IStorageProvider provider, string path)
|
||||
{
|
||||
var bytes = await provider.ReadAsync(path);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user