41 lines
1.3 KiB
C#
41 lines
1.3 KiB
C#
namespace Zcbot.WindowsNode.Tests;
|
|
|
|
public sealed class PersistenceSafetyTests : IDisposable
|
|
{
|
|
private readonly string root = Path.Combine(
|
|
Path.GetTempPath(), "zcbot-persistence-tests", Guid.NewGuid().ToString("N"));
|
|
|
|
[Fact]
|
|
public void PathGuardAcceptsAChildAndRejectsTraversalOrRootedSegments()
|
|
{
|
|
var child = PathGuard.CombineUnderRoot(root, "jobs", "job-id", "state.json");
|
|
|
|
Assert.StartsWith(Path.GetFullPath(root), child, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Throws<InvalidDataException>(
|
|
() => PathGuard.CombineUnderRoot(root, "..", "outside.json"));
|
|
Assert.Throws<InvalidDataException>(
|
|
() => PathGuard.CombineUnderRoot(root, Path.GetPathRoot(root)!));
|
|
}
|
|
|
|
[Fact]
|
|
public void AtomicFileReplacesTheTargetAndLeavesNoTemporaryFile()
|
|
{
|
|
var path = Path.Combine(root, "jobs", "state.json");
|
|
|
|
AtomicFile.Write(path, [1, 2, 3], overwrite: false);
|
|
AtomicFile.Write(path, [4, 5], overwrite: true);
|
|
|
|
Assert.Equal([4, 5], File.ReadAllBytes(path));
|
|
Assert.Empty(Directory.EnumerateFiles(
|
|
Path.GetDirectoryName(path)!, "state.json.tmp-*"));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Directory.Exists(root))
|
|
{
|
|
Directory.Delete(root, recursive: true);
|
|
}
|
|
}
|
|
}
|