2021-04-29 03:24:59 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using LibHac.Common;
|
2020-05-12 22:17:06 +02:00
|
|
|
|
using LibHac.Fs;
|
2020-06-10 07:55:59 +02:00
|
|
|
|
using LibHac.Fs.Fsa;
|
2020-05-12 22:17:06 +02:00
|
|
|
|
using LibHac.FsSystem;
|
2022-02-06 00:12:29 +01:00
|
|
|
|
using LibHac.Tests.Fs;
|
2020-05-12 22:17:06 +02:00
|
|
|
|
using LibHac.Tests.Fs.IFileSystemTestBase;
|
2021-12-19 09:35:45 +01:00
|
|
|
|
using LibHac.Tools.Fs;
|
2020-05-12 22:17:06 +02:00
|
|
|
|
using Xunit;
|
|
|
|
|
|
2022-02-06 00:12:29 +01:00
|
|
|
|
namespace LibHac.Tests.FsSystem;
|
2021-11-14 20:08:57 +01:00
|
|
|
|
|
|
|
|
|
public class DirectorySaveDataFileSystemTests : CommittableIFileSystemTests
|
2020-05-12 22:17:06 +02:00
|
|
|
|
{
|
2021-11-14 20:08:57 +01:00
|
|
|
|
protected override IFileSystem CreateFileSystem()
|
2020-05-12 22:17:06 +02:00
|
|
|
|
{
|
2021-11-14 20:08:57 +01:00
|
|
|
|
return CreateFileSystemInternal().saveFs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override IReopenableFileSystemCreator GetFileSystemCreator()
|
|
|
|
|
{
|
|
|
|
|
return new DirectorySaveDataFileSystemCreator();
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
private class DirectorySaveDataFileSystemCreator : IReopenableFileSystemCreator
|
|
|
|
|
{
|
|
|
|
|
private IFileSystem BaseFileSystem { get; }
|
|
|
|
|
|
|
|
|
|
public DirectorySaveDataFileSystemCreator()
|
2020-05-12 22:17:06 +02:00
|
|
|
|
{
|
2021-11-14 20:08:57 +01:00
|
|
|
|
BaseFileSystem = new InMemoryFileSystem();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
public IFileSystem Create()
|
2020-05-12 22:17:06 +02:00
|
|
|
|
{
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, BaseFileSystem, true, true, true)
|
|
|
|
|
.ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
return saveFs;
|
2020-05-12 22:17:06 +02:00
|
|
|
|
}
|
2021-11-14 20:08:57 +01:00
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
public static Result CreateDirSaveFs(out DirectorySaveDataFileSystem created, IFileSystem baseFileSystem,
|
|
|
|
|
ISaveDataCommitTimeStampGetter timeStampGetter, RandomDataGenerator randomGenerator,
|
|
|
|
|
bool isJournalingSupported, bool isMultiCommitSupported, bool isJournalingEnabled,
|
|
|
|
|
FileSystemClient fsClient)
|
|
|
|
|
{
|
|
|
|
|
var obj = new DirectorySaveDataFileSystem(baseFileSystem, fsClient);
|
2022-11-10 05:33:27 +01:00
|
|
|
|
Result res = obj.Initialize(isJournalingSupported, isMultiCommitSupported, isJournalingEnabled, timeStampGetter,
|
2022-04-23 21:38:10 +02:00
|
|
|
|
randomGenerator);
|
2021-08-10 23:44:58 +02:00
|
|
|
|
|
2022-11-10 05:33:27 +01:00
|
|
|
|
if (res.IsSuccess())
|
2021-08-10 23:44:58 +02:00
|
|
|
|
{
|
2021-11-14 20:08:57 +01:00
|
|
|
|
created = obj;
|
|
|
|
|
return Result.Success;
|
2021-08-10 23:44:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
obj.Dispose();
|
|
|
|
|
UnsafeHelpers.SkipParamInit(out created);
|
2022-11-10 05:33:27 +01:00
|
|
|
|
return res;
|
2021-11-14 20:08:57 +01:00
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
public static Result CreateDirSaveFs(out DirectorySaveDataFileSystem created, IFileSystem baseFileSystem,
|
|
|
|
|
bool isJournalingSupported, bool isMultiCommitSupported, bool isJournalingEnabled)
|
|
|
|
|
{
|
|
|
|
|
return CreateDirSaveFs(out created, baseFileSystem, null, null, isJournalingSupported, isMultiCommitSupported,
|
|
|
|
|
isJournalingEnabled, null);
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
private (IFileSystem baseFs, DirectorySaveDataFileSystem saveFs) CreateFileSystemInternal()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
return (baseFs, saveFs);
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
2022-02-06 00:12:29 +01:00
|
|
|
|
public void CreateFile_CreatedInModifiedDirectory()
|
2021-11-14 20:08:57 +01:00
|
|
|
|
{
|
|
|
|
|
(IFileSystem baseFs, IFileSystem saveFs) = CreateFileSystemInternal();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CreateFile("/file", 0, CreateFileOptions.None);
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(baseFs.GetEntryType(out DirectoryEntryType type, "/1/file"));
|
|
|
|
|
Assert.Equal(DirectoryEntryType.File, type);
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void CreateFile_NotCreatedInCommittedDirectory()
|
|
|
|
|
{
|
|
|
|
|
(IFileSystem baseFs, IFileSystem saveFs) = CreateFileSystemInternal();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CreateFile("/file", 0, CreateFileOptions.None);
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Result(ResultFs.PathNotFound, baseFs.GetEntryType(out _, "/0/file"));
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Commit_FileExistsInCommittedDirectory()
|
|
|
|
|
{
|
|
|
|
|
(IFileSystem baseFs, IFileSystem saveFs) = CreateFileSystemInternal();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CreateFile("/file", 0, CreateFileOptions.None);
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(saveFs.Commit());
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(baseFs.GetEntryType(out DirectoryEntryType type, "/0/file"));
|
|
|
|
|
Assert.Equal(DirectoryEntryType.File, type);
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Rollback_FileDoesNotExistInBaseAfterRollback()
|
|
|
|
|
{
|
|
|
|
|
(IFileSystem baseFs, IFileSystem saveFs) = CreateFileSystemInternal();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CreateFile("/file", 0, CreateFileOptions.None);
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Rollback should succeed
|
|
|
|
|
Assert.Success(saveFs.Rollback());
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Make sure all the files are gone
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file"));
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, baseFs.GetEntryType(out _, "/0/file"));
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, baseFs.GetEntryType(out _, "/1/file"));
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Rollback_DeletedFileIsRestoredInBaseAfterRollback()
|
|
|
|
|
{
|
|
|
|
|
(IFileSystem baseFs, IFileSystem saveFs) = CreateFileSystemInternal();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CreateFile("/file", 0, CreateFileOptions.None);
|
|
|
|
|
saveFs.Commit();
|
|
|
|
|
saveFs.DeleteFile("/file");
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Rollback should succeed
|
|
|
|
|
Assert.Success(saveFs.Rollback());
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Make sure all the files are restored
|
|
|
|
|
Assert.Success(saveFs.GetEntryType(out _, "/file"));
|
|
|
|
|
Assert.Success(baseFs.GetEntryType(out _, "/0/file"));
|
|
|
|
|
Assert.Success(baseFs.GetEntryType(out _, "/1/file"));
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_NormalState_UsesCommittedData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
baseFs.CreateDirectory("/0").ThrowIfFailure();
|
|
|
|
|
baseFs.CreateDirectory("/1").ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Set the existing files before initializing the save FS
|
|
|
|
|
baseFs.CreateFile("/0/file1", 0, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(saveFs.GetEntryType(out _, "/file1"));
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file2"));
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
2022-02-06 00:12:29 +01:00
|
|
|
|
public void Initialize_InterruptedAfterCommitPart1_UsesModifiedData()
|
2021-11-14 20:08:57 +01:00
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
baseFs.CreateDirectory("/_").ThrowIfFailure();
|
|
|
|
|
baseFs.CreateDirectory("/1").ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Set the existing files before initializing the save FS
|
|
|
|
|
baseFs.CreateFile("/_/file1", 0, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
|
|
|
|
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
|
|
|
|
}
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
2022-02-06 00:12:29 +01:00
|
|
|
|
public void Initialize_InterruptedDuringCommitPart2_UsesModifiedData()
|
2021-11-14 20:08:57 +01:00
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
baseFs.CreateDirectory("/1").ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Set the existing files before initializing the save FS
|
|
|
|
|
baseFs.CreateFile("/1/file2", 0, CreateFileOptions.None).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Result(ResultFs.PathNotFound, saveFs.GetEntryType(out _, "/file1"));
|
|
|
|
|
Assert.Success(saveFs.GetEntryType(out _, "/file2"));
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_InitialExtraDataIsEmpty()
|
|
|
|
|
{
|
|
|
|
|
(IFileSystem _, DirectorySaveDataFileSystem saveFs) = CreateFileSystemInternal();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
|
|
|
|
Assert.True(SpanHelpers.AsByteSpan(ref extraData).IsZeros());
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void WriteExtraData_CanReadBackExtraData()
|
|
|
|
|
{
|
|
|
|
|
(IFileSystem _, DirectorySaveDataFileSystem saveFs) = CreateFileSystemInternal();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
var originalExtraData = new SaveDataExtraData();
|
|
|
|
|
originalExtraData.DataSize = 0x12345;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(saveFs.WriteExtraData(in originalExtraData));
|
|
|
|
|
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
|
|
|
|
Assert.Equal(originalExtraData, extraData);
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Commit_AfterSuccessfulCommit_CanReadCommittedExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
var originalExtraData = new SaveDataExtraData();
|
|
|
|
|
originalExtraData.DataSize = 0x12345;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.WriteExtraData(in originalExtraData).ThrowIfFailure();
|
|
|
|
|
Assert.Success(saveFs.CommitExtraData(false));
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.Dispose();
|
|
|
|
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
|
|
|
|
Assert.Equal(originalExtraData, extraData);
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Rollback_WriteExtraDataThenRollback_ExtraDataIsRolledBack()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
var originalExtraData = new SaveDataExtraData();
|
|
|
|
|
originalExtraData.DataSize = 0x12345;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.WriteExtraData(in originalExtraData).ThrowIfFailure();
|
|
|
|
|
saveFs.CommitExtraData(false).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.Dispose();
|
|
|
|
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
var newExtraData = new SaveDataExtraData();
|
|
|
|
|
newExtraData.DataSize = 0x67890;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.WriteExtraData(in newExtraData).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Success(saveFs.Rollback());
|
|
|
|
|
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Equal(originalExtraData, extraData);
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Rollback_WriteExtraDataThenCloseFs_ExtraDataIsRolledBack()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Write extra data and close with committing
|
|
|
|
|
var originalExtraData = new SaveDataExtraData();
|
|
|
|
|
originalExtraData.DataSize = 0x12345;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.WriteExtraData(in originalExtraData).ThrowIfFailure();
|
|
|
|
|
saveFs.CommitExtraData(false).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.Dispose();
|
|
|
|
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Write a new extra data and close without committing
|
|
|
|
|
var newExtraData = new SaveDataExtraData();
|
|
|
|
|
newExtraData.DataSize = 0x67890;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.WriteExtraData(in newExtraData).ThrowIfFailure();
|
|
|
|
|
saveFs.Dispose();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
// Read extra data should match the first one
|
|
|
|
|
CreateDirSaveFs(out saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
Assert.Success(saveFs.ReadExtraData(out SaveDataExtraData extraData));
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Equal(originalExtraData, extraData);
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
2022-02-06 00:12:29 +01:00
|
|
|
|
public void Initialize_InterruptedAfterCommitPart1_UsesModifiedExtraData()
|
2021-11-14 20:08:57 +01:00
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
2021-07-19 22:16:11 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x12345).ThrowIfFailure();
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
2021-07-19 22:16:11 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
2021-07-19 22:16:11 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Assert.Equal(0x67890, extraData.DataSize);
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2022-02-06 00:12:29 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_OnlySynchronizingExtraDataExists_UsesSynchronizingExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x67890).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(0x67890, extraData.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_OnlyCommittedExtraDataExists_UsesCommittedExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData0", 0x67890).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(0x67890, extraData.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_OnlyModifiedExtraDataExists_UsesModifiedExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(0x67890, extraData.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_SynchronizingAndCommittedExtraDataExist_UsesCommittedExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x12345).ThrowIfFailure();
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData0", 0x67890).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(0x67890, extraData.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_SynchronizingAndModifiedExtraDataExist_UsesModifiedExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x12345).ThrowIfFailure();
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(0x67890, extraData.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_CommittedAndModifiedExtraDataExist_UsesCommittedExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData0", 0x12345).ThrowIfFailure();
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(0x12345, extraData.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Initialize_AllThreeExtraDataFilesExist_UsesCommittedExtraData()
|
|
|
|
|
{
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData_", 0x12345).ThrowIfFailure();
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData0", 0x54321).ThrowIfFailure();
|
|
|
|
|
CreateExtraDataForTest(baseFs, "/ExtraData1", 0x67890).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, true, true, true).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(0x54321, extraData.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void CommitSaveData_MultipleCommits_CommitIdIsUpdatedSkippingInvalidIds()
|
|
|
|
|
{
|
|
|
|
|
var random = new RandomGenerator();
|
|
|
|
|
RandomDataGenerator randomGeneratorFunc = buffer => random.GenerateRandom(buffer);
|
|
|
|
|
var timeStampGetter = new TimeStampGetter();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
|
|
|
|
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(2, extraData.CommitId);
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(3, extraData.CommitId);
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(6, extraData.CommitId);
|
2021-07-19 22:16:11 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(2, extraData.CommitId);
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void CommitSaveData_MultipleCommits_TimeStampUpdated()
|
|
|
|
|
{
|
|
|
|
|
var random = new RandomGenerator();
|
|
|
|
|
RandomDataGenerator randomGeneratorFunc = buffer => random.GenerateRandom(buffer);
|
|
|
|
|
var timeStampGetter = new TimeStampGetter();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
|
|
|
|
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(1u, extraData.TimeStamp);
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(2u, extraData.TimeStamp);
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(3u, extraData.TimeStamp);
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(4u, extraData.TimeStamp);
|
|
|
|
|
}
|
2021-07-19 22:16:11 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
[Fact]
|
|
|
|
|
public void CommitSaveData_UpdateTimeStampIsFalse_TimeStampAndCommitIdAreNotUpdated()
|
|
|
|
|
{
|
|
|
|
|
var random = new RandomGenerator();
|
|
|
|
|
RandomDataGenerator randomGeneratorFunc = buffer => random.GenerateRandom(buffer);
|
|
|
|
|
var timeStampGetter = new TimeStampGetter();
|
|
|
|
|
|
|
|
|
|
var baseFs = new InMemoryFileSystem();
|
|
|
|
|
CreateDirSaveFs(out DirectorySaveDataFileSystem saveFs, baseFs, timeStampGetter,
|
|
|
|
|
randomGeneratorFunc, true, true, true, null).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out SaveDataExtraData extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(1u, extraData.TimeStamp);
|
|
|
|
|
Assert.Equal(2, extraData.CommitId);
|
|
|
|
|
|
|
|
|
|
saveFs.CommitExtraData(false).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(1u, extraData.TimeStamp);
|
|
|
|
|
Assert.Equal(2, extraData.CommitId);
|
|
|
|
|
|
|
|
|
|
saveFs.CommitExtraData(true).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(2u, extraData.TimeStamp);
|
|
|
|
|
Assert.Equal(3, extraData.CommitId);
|
|
|
|
|
|
|
|
|
|
saveFs.CommitExtraData(false).ThrowIfFailure();
|
|
|
|
|
saveFs.ReadExtraData(out extraData).ThrowIfFailure();
|
|
|
|
|
Assert.Equal(2u, extraData.TimeStamp);
|
|
|
|
|
Assert.Equal(3, extraData.CommitId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class TimeStampGetter : ISaveDataCommitTimeStampGetter
|
|
|
|
|
{
|
|
|
|
|
private long _currentTimeStamp = 1;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
public Result Get(out long timeStamp)
|
2021-04-29 03:24:59 +02:00
|
|
|
|
{
|
2021-11-14 20:08:57 +01:00
|
|
|
|
timeStamp = _currentTimeStamp++;
|
|
|
|
|
return Result.Success;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
private class RandomGenerator
|
|
|
|
|
{
|
|
|
|
|
private static readonly int[] Values = { 2, 0, 3, 3, 6, 0 };
|
|
|
|
|
|
|
|
|
|
private int _index;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2022-04-23 21:38:10 +02:00
|
|
|
|
public void GenerateRandom(Span<byte> output)
|
2021-11-14 20:08:57 +01:00
|
|
|
|
{
|
|
|
|
|
if (output.Length != 8)
|
|
|
|
|
throw new ArgumentException();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
Unsafe.As<byte, long>(ref MemoryMarshal.GetReference(output)) = Values[_index];
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
_index = (_index + 1) % Values.Length;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
}
|
2021-11-14 20:08:57 +01:00
|
|
|
|
}
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
private Result CreateExtraDataForTest(IFileSystem fileSystem, string path, int saveDataSize)
|
|
|
|
|
{
|
|
|
|
|
fileSystem.DeleteFile(path).IgnoreResult();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2022-11-10 05:33:27 +01:00
|
|
|
|
Result res = fileSystem.CreateFile(path, Unsafe.SizeOf<SaveDataExtraData>());
|
|
|
|
|
if (res.IsFailure()) return res.Miss();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
var extraData = new SaveDataExtraData();
|
|
|
|
|
extraData.DataSize = saveDataSize;
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
using var file = new UniqueRef<IFile>();
|
2022-11-10 05:33:27 +01:00
|
|
|
|
res = fileSystem.OpenFile(ref file.Ref(), path, OpenMode.ReadWrite);
|
|
|
|
|
if (res.IsFailure()) return res.Miss();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2022-11-10 05:33:27 +01:00
|
|
|
|
res = file.Get.Write(0, SpanHelpers.AsByteSpan(ref extraData), WriteOption.Flush);
|
|
|
|
|
if (res.IsFailure()) return res.Miss();
|
2021-04-29 03:24:59 +02:00
|
|
|
|
|
2021-11-14 20:08:57 +01:00
|
|
|
|
return Result.Success;
|
2020-05-12 22:17:06 +02:00
|
|
|
|
}
|
2021-12-19 09:35:45 +01:00
|
|
|
|
}
|