2020-03-04 02:19:11 +01:00
|
|
|
|
using System;
|
|
|
|
|
using LibHac.Common;
|
|
|
|
|
using LibHac.Fs;
|
2020-06-10 07:55:59 +02:00
|
|
|
|
using LibHac.Fs.Fsa;
|
2020-03-04 02:19:11 +01:00
|
|
|
|
using LibHac.FsSystem;
|
2020-10-11 05:17:07 +02:00
|
|
|
|
using LibHac.Util;
|
2020-03-04 02:19:11 +01:00
|
|
|
|
using Xunit;
|
|
|
|
|
|
|
|
|
|
namespace LibHac.Tests.Fs
|
|
|
|
|
{
|
|
|
|
|
public class LayeredFileSystemTests
|
|
|
|
|
{
|
|
|
|
|
private IFileSystem CreateFileSystem()
|
|
|
|
|
{
|
|
|
|
|
var lowerLayerFs = new InMemoryFileSystem();
|
|
|
|
|
var upperLayerFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
var layeredFs = new LayeredFileSystem(lowerLayerFs, upperLayerFs);
|
|
|
|
|
|
2021-07-19 22:16:11 +02:00
|
|
|
|
lowerLayerFs.CreateDirectory("/dir").ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateDirectory("/dir").ThrowIfFailure();
|
|
|
|
|
lowerLayerFs.CreateDirectory("/dir2").ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateDirectory("/dir2").ThrowIfFailure();
|
|
|
|
|
lowerLayerFs.CreateDirectory("/dir3").ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateDirectory("/dir3").ThrowIfFailure();
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-07-19 22:16:11 +02:00
|
|
|
|
lowerLayerFs.CreateDirectory("/lowerDir").ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateDirectory("/upperDir").ThrowIfFailure();
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-07-19 22:16:11 +02:00
|
|
|
|
lowerLayerFs.CreateFile("/dir/replacedFile", 1, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateFile("/dir/replacedFile", 2, CreateFileOptions.None).ThrowIfFailure();
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-07-19 22:16:11 +02:00
|
|
|
|
lowerLayerFs.CreateFile("/dir2/lowerFile", 0, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateFile("/dir2/upperFile", 0, CreateFileOptions.None).ThrowIfFailure();
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-07-19 22:16:11 +02:00
|
|
|
|
lowerLayerFs.CreateFile("/dir3/lowerFile", 0, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateFile("/dir3/upperFile", 2, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
lowerLayerFs.CreateFile("/dir3/replacedFile", 1, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateFile("/dir3/replacedFile", 2, CreateFileOptions.None).ThrowIfFailure();
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-07-19 22:16:11 +02:00
|
|
|
|
lowerLayerFs.CreateFile("/replacedWithDir", 0, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateDirectory("/replacedWithDir").ThrowIfFailure();
|
|
|
|
|
upperLayerFs.CreateFile("/replacedWithDir/subFile", 0, CreateFileOptions.None).ThrowIfFailure();
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
|
|
|
|
return layeredFs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IFileSystem CreateEmptyFileSystem()
|
|
|
|
|
{
|
|
|
|
|
var baseLayerFs = new InMemoryFileSystem();
|
|
|
|
|
var topLayerFs = new InMemoryFileSystem();
|
|
|
|
|
|
|
|
|
|
return new LayeredFileSystem(baseLayerFs, topLayerFs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void OpenFile_FileDoesNotExist_ReturnsPathNotFound()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var file = new UniqueRef<IFile>();
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, fs.OpenFile(ref file.Ref(), "/fakefile", OpenMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void OpenFile_FileIsInBothSources_ReturnsFileFromTopSource()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var file = new UniqueRef<IFile>();
|
|
|
|
|
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir/replacedFile", OpenMode.All));
|
|
|
|
|
Assert.Success(file.Get.GetSize(out long fileSize));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
|
|
|
|
Assert.Equal(2, fileSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void OpenFile_InsideMergedDirectory_CanOpenFilesFromBothSources()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var file = new UniqueRef<IFile>();
|
|
|
|
|
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir2/lowerFile", OpenMode.All));
|
|
|
|
|
Assert.Success(fs.OpenFile(ref file.Ref(), "/dir2/upperFile", OpenMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void OpenDirectory_DirDoesNotExist_ReturnsPathNotFound()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, fs.OpenDirectory(ref directory.Ref(), "/fakedir", OpenDirectoryMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void OpenDirectory_ExistsInSingleLayer_ReturnsNonMergedDirectory()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/lowerDir", OpenDirectoryMode.All));
|
|
|
|
|
Assert.Equal(typeof(InMemoryFileSystem), directory.Get.GetType().DeclaringType);
|
2020-03-04 02:19:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void OpenDirectory_ExistsInMultipleLayers_ReturnsMergedDirectory()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir", OpenDirectoryMode.All));
|
|
|
|
|
Assert.Equal(typeof(LayeredFileSystem), directory.Get.GetType().DeclaringType);
|
2020-03-04 02:19:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void GetEntryType_InsideMergedDirectory_CanGetEntryTypesFromBothSources()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-07-19 22:16:11 +02:00
|
|
|
|
Assert.Success(fs.GetEntryType(out _, "/dir2/lowerFile"));
|
|
|
|
|
Assert.Success(fs.GetEntryType(out _, "/dir2/upperFile"));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void IDirectoryRead_DuplicatedEntriesAreReturnedOnlyOnce()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
Span<DirectoryEntry> entries = stackalloc DirectoryEntry[4];
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir3", OpenDirectoryMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
Assert.Success(directory.Get.Read(out long entriesRead, entries));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
Assert.Equal(3, entriesRead);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void IDirectoryRead_DuplicatedEntryReturnsFromTopLayer()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
var entry = new DirectoryEntry();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir", OpenDirectoryMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
Assert.Success(directory.Get.Read(out _, SpanHelpers.AsSpan(ref entry)));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
Assert.Equal("replacedFile", StringUtils.Utf8ZToString(entry.Name));
|
|
|
|
|
Assert.Equal(2, entry.Size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void IDirectoryRead_EmptyFs_NoEntriesAreRead()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateEmptyFileSystem();
|
|
|
|
|
var entry = new DirectoryEntry();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/", OpenDirectoryMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
Assert.Success(directory.Get.Read(out long entriesRead, SpanHelpers.AsSpan(ref entry)));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
Assert.Equal(0, entriesRead);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void IDirectoryGetEntryCount_DuplicatedEntriesAreCountedOnlyOnce()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir3", OpenDirectoryMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
Assert.Equal(3, entryCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void IDirectoryGetEntryCount_MergedDirectoryAfterRead_AllEntriesAreCounted()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
var entry = new DirectoryEntry();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/dir3", OpenDirectoryMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
|
|
|
|
// Read all entries
|
|
|
|
|
long entriesRead;
|
|
|
|
|
do
|
|
|
|
|
{
|
2021-08-10 23:44:58 +02:00
|
|
|
|
Assert.Success(directory.Get.Read(out entriesRead, SpanHelpers.AsSpan(ref entry)));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
} while (entriesRead != 0);
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
Assert.Equal(3, entryCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void IDirectoryGetEntryCount_EmptyFs_EntryCountIsZero()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateEmptyFileSystem();
|
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
using var directory = new UniqueRef<IDirectory>();
|
|
|
|
|
Assert.Success(fs.OpenDirectory(ref directory.Ref(), "/", OpenDirectoryMode.All));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
|
2021-08-10 23:44:58 +02:00
|
|
|
|
Assert.Success(directory.Get.GetEntryCount(out long entryCount));
|
2020-03-04 02:19:11 +01:00
|
|
|
|
Assert.Equal(0, entryCount);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|