diff --git a/src/LibHac/Fs/AttributeFileSystemBase.cs b/src/LibHac/Fs/AttributeFileSystemBase.cs
index c7011cf5..de0997c1 100644
--- a/src/LibHac/Fs/AttributeFileSystemBase.cs
+++ b/src/LibHac/Fs/AttributeFileSystemBase.cs
@@ -14,7 +14,7 @@
return CreateDirectoryImpl(path, archiveAttribute);
}
- public Result GetFileAttributes(string path, out NxFileAttributes attributes)
+ public Result GetFileAttributes(out NxFileAttributes attributes, string path)
{
if (IsDisposed)
{
diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs
index 5e8323b7..675ad632 100644
--- a/src/LibHac/Fs/FileBase.cs
+++ b/src/LibHac/Fs/FileBase.cs
@@ -29,6 +29,7 @@ namespace LibHac.Fs
if (destination.Length == 0) return Result.Success;
if (offset < 0) return ResultFs.OutOfRange.Log();
+ if (long.MaxValue - offset < destination.Length) return ResultFs.OutOfRange.Log();
return ReadImpl(out bytesRead, offset, destination, options);
}
@@ -48,6 +49,7 @@ namespace LibHac.Fs
}
if (offset < 0) return ResultFs.OutOfRange.Log();
+ if (long.MaxValue - offset < source.Length) return ResultFs.OutOfRange.Log();
return WriteImpl(offset, source, options);
}
diff --git a/src/LibHac/Fs/IAttributeFileSystem.cs b/src/LibHac/Fs/IAttributeFileSystem.cs
index 1936e8db..cc37a807 100644
--- a/src/LibHac/Fs/IAttributeFileSystem.cs
+++ b/src/LibHac/Fs/IAttributeFileSystem.cs
@@ -3,7 +3,7 @@
public interface IAttributeFileSystem : IFileSystem
{
Result CreateDirectory(string path, NxFileAttributes archiveAttribute);
- Result GetFileAttributes(string path, out NxFileAttributes attributes);
+ Result GetFileAttributes(out NxFileAttributes attributes, string path);
Result SetFileAttributes(string path, NxFileAttributes attributes);
Result GetFileSize(out long fileSize, string path);
}
diff --git a/src/LibHac/FsSystem/ConcatenationFileSystem.cs b/src/LibHac/FsSystem/ConcatenationFileSystem.cs
index 9b732f1f..9c543681 100644
--- a/src/LibHac/FsSystem/ConcatenationFileSystem.cs
+++ b/src/LibHac/FsSystem/ConcatenationFileSystem.cs
@@ -51,7 +51,7 @@ namespace LibHac.FsSystem
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- Result rc = BaseFileSystem.GetFileAttributes(path, out NxFileAttributes attributes);
+ Result rc = BaseFileSystem.GetFileAttributes(out NxFileAttributes attributes, path);
if (rc.IsFailure()) return false;
return HasConcatenationFileAttribute(attributes);
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IAttributeFileSystemTests.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IAttributeFileSystemTests.cs
new file mode 100644
index 00000000..2dcef3c2
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IAttributeFileSystemTests.cs
@@ -0,0 +1,136 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract class IAttributeFileSystemTests : IFileSystemTests
+ {
+ protected abstract IAttributeFileSystem CreateAttributeFileSystem();
+
+ [Fact]
+ public void CreateDirectory_WithoutArchiveAttribute_ArchiveFlagIsNotSet()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+
+ Assert.True(fs.CreateDirectory("/dir", NxFileAttributes.None).IsSuccess());
+
+ Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir").IsSuccess());
+ Assert.Equal(NxFileAttributes.Directory, attributes);
+ }
+
+ [Fact]
+ public void CreateDirectory_WithArchiveAttribute_ArchiveFlagIsSet()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+
+ Assert.True(fs.CreateDirectory("/dir", NxFileAttributes.Archive).IsSuccess());
+
+ Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir").IsSuccess());
+ Assert.Equal(NxFileAttributes.Directory | NxFileAttributes.Archive, attributes);
+ }
+
+ [Fact]
+ public void GetFileAttributes_AttributesOnNewFileAreEmpty()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/file");
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(NxFileAttributes.None, attributes);
+ }
+
+ [Fact]
+ public void GetFileAttributes_AttributesOnNewDirHaveOnlyDirFlagSet()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+ fs.CreateDirectory("/dir");
+
+ Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir");
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(NxFileAttributes.Directory, attributes);
+ }
+
+ [Fact]
+ public void GetFileAttributes_PathDoesNotExist_ReturnsPathNotFound()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+
+ Result rc = fs.GetFileAttributes(out _, "/path");
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void SetFileAttributes_PathDoesNotExist_ReturnsPathNotFound()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+
+ Result rc = fs.SetFileAttributes("/path", NxFileAttributes.None);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void SetFileAttributes_SetAttributeOnFile()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Result rcSet = fs.SetFileAttributes("/file", NxFileAttributes.Archive);
+ Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/file");
+
+ Assert.True(rcSet.IsSuccess());
+ Assert.True(rcGet.IsSuccess());
+ Assert.Equal(NxFileAttributes.Archive, attributes);
+ }
+
+ [Fact]
+ public void SetFileAttributes_SetAttributeOnDirectory()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+ fs.CreateDirectory("/dir");
+
+ Result rcSet = fs.SetFileAttributes("/dir", NxFileAttributes.Archive);
+ Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir");
+
+ Assert.True(rcSet.IsSuccess());
+ Assert.True(rcGet.IsSuccess());
+ Assert.Equal(NxFileAttributes.Directory | NxFileAttributes.Archive, attributes);
+ }
+
+ [Fact]
+ public void GetFileSize_ReadNewFileSize()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+
+ fs.CreateFile("/file", 845, CreateFileOptions.None);
+
+ Assert.True(fs.GetFileSize(out long fileSize, "/file").IsSuccess());
+ Assert.Equal(845, fileSize);
+ }
+
+ [Fact]
+ public void GetFileSize_PathDoesNotExist_ReturnsPathNotFound()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+
+ Result rc = fs.GetFileSize(out _, "/path");
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void GetFileSize_PathIsDirectory_ReturnsPathNotFound()
+ {
+ IAttributeFileSystem fs = CreateAttributeFileSystem();
+ fs.CreateDirectory("/dir");
+
+ Result rc = fs.GetFileSize(out _, "/dir");
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+ }
+}
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CleanDirectoryRecursively.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CleanDirectoryRecursively.cs
new file mode 100644
index 00000000..c9a8a901
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CleanDirectoryRecursively.cs
@@ -0,0 +1,32 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void CleanDirectoryRecursively_DeletesChildren()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+ fs.CreateDirectory("/dir/dir2");
+ fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
+
+ Result rcDelete = fs.CleanDirectoryRecursively("/dir");
+
+ Result rcDir1Type = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir");
+ Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2");
+ Result rcFileType = fs.GetEntryType(out _, "/dir/file1");
+
+ Assert.True(rcDelete.IsSuccess());
+
+ Assert.True(rcDir1Type.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, dir1Type);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rcDir2Type);
+ Assert.Equal(ResultFs.PathNotFound.Value, rcFileType);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateDirectory.cs
new file mode 100644
index 00000000..8a7eb9b5
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateDirectory.cs
@@ -0,0 +1,103 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void CreateDirectory_EntryIsAdded()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+ Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir");
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, type);
+ }
+
+ [Fact]
+ public void CreateDirectory_DirectoryExists_ReturnsPathAlreadyExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+
+ Result rc = fs.CreateDirectory("/dir");
+
+ Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
+ }
+
+ [Fact]
+ public void CreateDirectory_FileExists_ReturnsPathAlreadyExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Result rc = fs.CreateDirectory("/file");
+
+ Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
+ }
+
+ [Fact]
+ public void CreateDirectory_ParentDoesNotExist_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ Result rc = fs.CreateFile("/dir1/dir2", 0, CreateFileOptions.None);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void CreateDirectory_WithTrailingSeparator_EntryIsAdded()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir/");
+ Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir/");
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, type);
+ }
+
+ [Fact]
+ public void CreateDirectory_MultipleSiblings()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir1");
+ fs.CreateDirectory("/dir2");
+
+ Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1");
+ Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2");
+
+ Assert.True(rc1.IsSuccess());
+ Assert.True(rc2.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, type1);
+ Assert.Equal(DirectoryEntryType.Directory, type2);
+ }
+
+ [Fact]
+ public void CreateDirectory_InChildDirectory()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir1");
+ fs.CreateDirectory("/dir2");
+
+ fs.CreateDirectory("/dir1/dir1a");
+ fs.CreateDirectory("/dir2/dir2a");
+
+ Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/dir1a");
+ Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/dir2a");
+
+ Assert.True(rc1.IsSuccess());
+ Assert.True(rc2.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, type1);
+ Assert.Equal(DirectoryEntryType.Directory, type2);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateFile.cs
new file mode 100644
index 00000000..ca251868
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateFile.cs
@@ -0,0 +1,119 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void CreateFile_EntryIsAdded()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+ Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file");
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(DirectoryEntryType.File, type);
+ }
+
+ [Fact]
+ public void CreateFile_DirectoryExists_ReturnsPathAlreadyExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+
+ Result rc = fs.CreateFile("/dir", 0, CreateFileOptions.None);
+
+ Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
+ }
+
+ [Fact]
+ public void CreateFile_FileExists_ReturnsPathAlreadyExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Result rc = fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
+ }
+
+ [Fact]
+ public void CreateFile_ParentDoesNotExist_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ Result rc = fs.CreateFile("/dir/file", 0, CreateFileOptions.None);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void CreateFile_WithTrailingSeparator_EntryIsAdded()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file/", 0, CreateFileOptions.None);
+ Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file/");
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(DirectoryEntryType.File, type);
+ }
+
+ [Fact]
+ public void CreateFile_WithSize_SizeIsSet()
+ {
+ const long expectedSize = 12345;
+
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", expectedSize, CreateFileOptions.None);
+
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ Result rc = file.GetSize(out long fileSize);
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(expectedSize, fileSize);
+ }
+
+ [Fact]
+ public void CreateFile_MultipleSiblings()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file1", 0, CreateFileOptions.None);
+ fs.CreateFile("/file2", 0, CreateFileOptions.None);
+
+ Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/file1");
+ Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/file2");
+
+ Assert.True(rc1.IsSuccess());
+ Assert.True(rc2.IsSuccess());
+ Assert.Equal(DirectoryEntryType.File, type1);
+ Assert.Equal(DirectoryEntryType.File, type2);
+ }
+
+ [Fact]
+ public void CreateFile_InChildDirectory()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir1");
+ fs.CreateDirectory("/dir2");
+
+ fs.CreateFile("/dir1/file1", 0, CreateFileOptions.None);
+ fs.CreateFile("/dir2/file2", 0, CreateFileOptions.None);
+
+ Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/file1");
+ Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/file2");
+
+ Assert.True(rc1.IsSuccess());
+ Assert.True(rc2.IsSuccess());
+ Assert.Equal(DirectoryEntryType.File, type1);
+ Assert.Equal(DirectoryEntryType.File, type2);
+ }
+ }
+}
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectory.cs
new file mode 100644
index 00000000..527b9be3
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectory.cs
@@ -0,0 +1,95 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void DeleteDirectory_DoesNotExist_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ Result rc = fs.DeleteDirectory("/dir");
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void DeleteDirectory_DirectoryExists_EntryIsRemoved()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+
+ Result rcDelete = fs.DeleteDirectory("/dir");
+ Result rcEntry = fs.GetEntryType(out _, "/dir");
+
+ Assert.True(rcDelete.IsSuccess());
+ Assert.Equal(ResultFs.PathNotFound.Value, rcEntry);
+ }
+
+ [Fact]
+ public void DeleteDirectory_PathIsFile_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Result rc = fs.DeleteDirectory("/file");
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void DeleteDirectory_HasOlderSibling_SiblingNotDeleted()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir1");
+ fs.CreateDirectory("/dir2");
+
+ Result rcDelete = fs.DeleteDirectory("/dir2");
+ Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
+ Result rcEntry2 = fs.GetEntryType(out _, "/dir2");
+
+ Assert.True(rcDelete.IsSuccess());
+ Assert.True(rcEntry1.IsSuccess());
+ Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
+
+ Assert.Equal(DirectoryEntryType.Directory, dir1Type);
+ }
+
+ [Fact]
+ public void DeleteDirectory_HasYoungerSibling_SiblingNotDeleted()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir2");
+ fs.CreateDirectory("/dir1");
+
+ Result rcDelete = fs.DeleteDirectory("/dir2");
+ Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
+ Result rcEntry2 = fs.GetEntryType(out _, "/dir2");
+
+ Assert.True(rcDelete.IsSuccess());
+ Assert.True(rcEntry1.IsSuccess());
+ Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
+
+ Assert.Equal(DirectoryEntryType.Directory, dir1Type);
+ }
+
+ [Fact]
+ public void DeleteDirectory_NotEmpty_ReturnsDirectoryNotEmpty()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+ fs.CreateFile("/dir/file", 0, CreateFileOptions.None);
+
+ Result rc = fs.DeleteDirectory("/dir");
+
+ Assert.Equal(ResultFs.DirectoryNotEmpty.Value, rc);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectoryRecursively.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectoryRecursively.cs
new file mode 100644
index 00000000..6dfe38f8
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectoryRecursively.cs
@@ -0,0 +1,30 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void DeleteDirectoryRecursively_DeletesDirectoryAndChildren()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+ fs.CreateDirectory("/dir/dir2");
+ fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
+
+ Result rcDelete = fs.DeleteDirectoryRecursively("/dir");
+
+ Result rcDir1Type = fs.GetEntryType(out _, "/dir");
+ Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2");
+ Result rcFileType = fs.GetEntryType(out _, "/dir/file1");
+
+ Assert.True(rcDelete.IsSuccess());
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rcDir1Type);
+ Assert.Equal(ResultFs.PathNotFound.Value, rcDir2Type);
+ Assert.Equal(ResultFs.PathNotFound.Value, rcFileType);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteFile.cs
new file mode 100644
index 00000000..bcaafd19
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteFile.cs
@@ -0,0 +1,81 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void DeleteFile_DoesNotExist_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ Result rc = fs.DeleteFile("/file");
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void DeleteFile_FileExists_FileEntryIsRemoved()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Result rcDelete = fs.DeleteFile("/file");
+ Result rcEntry = fs.GetEntryType(out _, "/file");
+
+ Assert.True(rcDelete.IsSuccess());
+ Assert.Equal(ResultFs.PathNotFound.Value, rcEntry);
+ }
+
+ [Fact]
+ public void DeleteFile_PathIsDirectory_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+
+ Result rc = fs.DeleteFile("/dir");
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void DeleteFile_HasOlderSibling_SiblingNotDeleted()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file1", 0, CreateFileOptions.None);
+ fs.CreateFile("/file2", 0, CreateFileOptions.None);
+
+ Result rcDelete = fs.DeleteFile("/file2");
+ Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1");
+ Result rcEntry2 = fs.GetEntryType(out _, "/file2");
+
+ Assert.True(rcDelete.IsSuccess());
+ Assert.True(rcEntry1.IsSuccess());
+ Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
+
+ Assert.Equal(DirectoryEntryType.File, dir1Type);
+ }
+
+ [Fact]
+ public void DeleteFile_HasYoungerSibling_SiblingNotDeleted()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file2", 0, CreateFileOptions.None);
+ fs.CreateFile("/file1", 0, CreateFileOptions.None);
+
+ Result rcDelete = fs.DeleteFile("/file2");
+ Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1");
+ Result rcEntry2 = fs.GetEntryType(out _, "/file2");
+
+ Assert.True(rcDelete.IsSuccess());
+ Assert.True(rcEntry1.IsSuccess());
+ Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
+
+ Assert.Equal(DirectoryEntryType.File, dir1Type);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.GetEntryType.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.GetEntryType.cs
new file mode 100644
index 00000000..f0758c4b
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.GetEntryType.cs
@@ -0,0 +1,29 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void GetEntryType_RootIsDirectory()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ Result rc = fs.GetEntryType(out DirectoryEntryType type, "/");
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, type);
+ }
+
+ [Fact]
+ public void GetEntryType_PathDoesNotExist_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ Result rc = fs.GetEntryType(out _, "/path");
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IDirectory.cs
new file mode 100644
index 00000000..50caf866
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IDirectory.cs
@@ -0,0 +1,82 @@
+using System;
+using LibHac.Common;
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void IDirectoryRead_AllEntriesAreReturned()
+ {
+ IFileSystem fs = CreateFileSystem();
+ fs.CreateDirectory("/dir");
+ fs.CreateDirectory("/dir/dir1");
+ fs.CreateFile("/dir/dir1/file1", 0, CreateFileOptions.None);
+ fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
+ fs.CreateFile("/dir/file2", 0, CreateFileOptions.None);
+
+ Result rc = fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All);
+ Assert.True(rc.IsSuccess());
+
+ var entry1 = new DirectoryEntry();
+ var entry2 = new DirectoryEntry();
+ var entry3 = new DirectoryEntry();
+ var entry4 = new DirectoryEntry();
+
+ Assert.True(dir.Read(out long entriesRead1, SpanHelpers.AsSpan(ref entry1)).IsSuccess());
+ Assert.True(dir.Read(out long entriesRead2, SpanHelpers.AsSpan(ref entry2)).IsSuccess());
+ Assert.True(dir.Read(out long entriesRead3, SpanHelpers.AsSpan(ref entry3)).IsSuccess());
+ Assert.True(dir.Read(out long entriesRead4, SpanHelpers.AsSpan(ref entry4)).IsSuccess());
+
+ Assert.Equal(1, entriesRead1);
+ Assert.Equal(1, entriesRead2);
+ Assert.Equal(1, entriesRead3);
+ Assert.Equal(0, entriesRead4);
+
+ bool dir1Read = false;
+ bool file1Read = false;
+ bool file2Read = false;
+
+ // Entries are not guaranteed to be in any particular order
+ CheckEntry(ref entry1);
+ CheckEntry(ref entry2);
+ CheckEntry(ref entry3);
+
+ Assert.True(dir1Read);
+ Assert.True(file1Read);
+ Assert.True(file2Read);
+
+ void CheckEntry(ref DirectoryEntry entry)
+ {
+ switch (StringUtils.Utf8ZToString(entry.Name))
+ {
+ case "dir1":
+ Assert.False(dir1Read);
+ Assert.Equal(DirectoryEntryType.Directory, entry.Type);
+
+ dir1Read = true;
+ break;
+
+ case "file1":
+ Assert.False(file1Read);
+ Assert.Equal(DirectoryEntryType.File, entry.Type);
+
+ file1Read = true;
+ break;
+
+ case "file2":
+ Assert.False(file2Read);
+ Assert.Equal(DirectoryEntryType.File, entry.Type);
+
+ file2Read = true;
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Read.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Read.cs
new file mode 100644
index 00000000..4d80d2e7
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Read.cs
@@ -0,0 +1,126 @@
+using System;
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void IFileRead_BytesReadContainsNumberOfBytesRead()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 100, CreateFileOptions.None);
+
+ var buffer = new byte[20];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Assert.True(file.Read(out long bytesRead, 50, buffer, ReadOption.None).IsSuccess());
+ Assert.Equal(20, bytesRead);
+ }
+ }
+
+ [Fact]
+ public void IFileRead_OffsetPastEndOfFile_ReturnsOutOfRange()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Result rc = file.Read(out _, 1, buffer, ReadOption.None);
+ Assert.Equal(ResultFs.OutOfRange.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileRead_OpenModeNoRead_ReturnsInvalidOpenModeForRead()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Write);
+ using (file)
+ {
+ Result rc = file.Read(out _, 0, buffer, ReadOption.None);
+ Assert.Equal(ResultFs.InvalidOpenModeForRead.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileRead_NegativeOffset_ReturnsOutOfRange()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Write);
+ using (file)
+ {
+ Result rc = file.Read(out _, -5, buffer, ReadOption.None);
+ Assert.Equal(ResultFs.OutOfRange.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileRead_OffsetPlusSizeOverflows_ReturnsOutOfRange()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Write);
+ using (file)
+ {
+ Result rc = file.Read(out _, long.MaxValue - 5, buffer, ReadOption.None);
+ Assert.Equal(ResultFs.OutOfRange.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileRead_FileTooSmallToFillBuffer_BytesReadContainsAvailableByteCount()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 100, CreateFileOptions.None);
+
+ var buffer = new byte[200];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Assert.True(file.Read(out long bytesRead, 90, buffer, ReadOption.None).IsSuccess());
+ Assert.Equal(10, bytesRead);
+ }
+ }
+
+ [Fact]
+ public void IFileRead_FileTooSmallToFillBuffer_DoesPartialRead()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 100, CreateFileOptions.None);
+
+ var bufferExpected = new byte[200];
+ bufferExpected.AsSpan(10).Fill(0xCC);
+
+ var buffer = new byte[200];
+ buffer.AsSpan().Fill(0xCC);
+
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Assert.True(file.Read(out _, 90, buffer, ReadOption.None).IsSuccess());
+ Assert.Equal(bufferExpected, buffer);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Size.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Size.cs
new file mode 100644
index 00000000..5ef77363
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Size.cs
@@ -0,0 +1,26 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void SetSize_FileSizeModified()
+ {
+ IFileSystem fs = CreateFileSystem();
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ fs.OpenFile(out IFile file, "/file", OpenMode.All);
+ Result rc = file.SetSize(54321);
+ file.Dispose();
+
+ fs.OpenFile(out file, "/file", OpenMode.All);
+ file.GetSize(out long fileSize);
+ file.Dispose();
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(54321, fileSize);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Write.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Write.cs
new file mode 100644
index 00000000..c6324d68
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Write.cs
@@ -0,0 +1,163 @@
+using System;
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void IFileWrite_CanReadBackWrittenData()
+ {
+ var data = new byte[] { 7, 4, 1, 0, 8, 5, 2, 9, 6, 3 };
+
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", data.Length, CreateFileOptions.None);
+
+ fs.OpenFile(out IFile file, "/file", OpenMode.Write);
+ file.Write(0, data, WriteOption.None);
+ file.Dispose();
+
+ var readData = new byte[data.Length];
+
+ fs.OpenFile(out file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Assert.True(file.Read(out long bytesRead, 0, readData, ReadOption.None).IsSuccess());
+ Assert.Equal(data.Length, bytesRead);
+ }
+
+ Assert.Equal(data, readData);
+ }
+
+ [Fact]
+ public void IFileWrite_WritePastEndOfFileWithNoAppend_ReturnsFileExtensionWithoutOpenModeAllowAppend()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 10, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Write);
+ using (file)
+ {
+ Result rc = file.Write(5, buffer, WriteOption.None);
+ Assert.Equal(ResultFs.FileExtensionWithoutOpenModeAllowAppend.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileWrite_OpenModeNoWrite_ReturnsInvalidOpenModeForWrite()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 10, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Result rc = file.Write(5, buffer, WriteOption.None);
+ Assert.Equal(ResultFs.InvalidOpenModeForWrite.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileWrite_NegativeOffset_ReturnsOutOfRange()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 10, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Result rc = file.Write(-5, buffer, WriteOption.None);
+ Assert.Equal(ResultFs.OutOfRange.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileWrite_OffsetPlusSizeOverflows_ReturnsOutOfRange()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 10, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.Read);
+ using (file)
+ {
+ Result rc = file.Write(long.MaxValue - 5, buffer, WriteOption.None);
+ Assert.Equal(ResultFs.OutOfRange.Value, rc);
+ }
+ }
+
+ [Fact]
+ public void IFileWrite_WritePartiallyPastEndOfFileAppendAllowed_FileIsExtended()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 10, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.All);
+ using (file)
+ {
+ Assert.True(file.Write(5, buffer, WriteOption.None).IsSuccess());
+
+ file.GetSize(out long newSize);
+ Assert.Equal(15, newSize);
+ }
+ }
+
+ [Fact]
+ public void IFileWrite_WritePastEndOfFileAppendAllowed_FileIsExtended()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 10, CreateFileOptions.None);
+
+ var buffer = new byte[10];
+ fs.OpenFile(out IFile file, "/file", OpenMode.All);
+ using (file)
+ {
+ Assert.True(file.Write(15, buffer, WriteOption.None).IsSuccess());
+
+ file.GetSize(out long newSize);
+ Assert.Equal(25, newSize);
+ }
+ }
+
+ [Fact]
+ public void IFileWrite_WritePastEndOfFileAppendAllowed_DataIsWritten()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 10, CreateFileOptions.None);
+
+ var bufferExpected = new byte[25];
+ bufferExpected.AsSpan(15).Fill(0xCC);
+
+ var writeBuffer = new byte[10];
+ writeBuffer.AsSpan().Fill(0xCC);
+
+ fs.OpenFile(out IFile file, "/file", OpenMode.All);
+ using (file)
+ {
+ file.Write(15, writeBuffer, WriteOption.None).IsSuccess();
+ }
+
+ var readBuffer = new byte[25];
+
+ fs.OpenFile(out file, "/file", OpenMode.Read);
+ using (file)
+ {
+ file.Read(out _, 0, readBuffer, ReadOption.None);
+ Assert.Equal(bufferExpected, readBuffer);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenDirectory.cs
new file mode 100644
index 00000000..c25edfdc
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenDirectory.cs
@@ -0,0 +1,20 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void OpenDirectory_PathIsFile_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+
+ Result rc = fs.OpenDirectory(out _, "/file", OpenDirectoryMode.All);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenFile.cs
new file mode 100644
index 00000000..4540d71b
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenFile.cs
@@ -0,0 +1,20 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void OpenFile_PathIsDirectory_ReturnsPathNotFound()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir");
+
+ Result rc = fs.OpenFile(out _, "/dir", OpenMode.All);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameDirectory.cs
new file mode 100644
index 00000000..72f81dc5
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameDirectory.cs
@@ -0,0 +1,107 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void RenameDirectory_EntriesAreMoved()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir1");
+ Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
+
+ Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
+ Result rcDir1 = fs.GetEntryType(out _, "/dir1");
+
+ Assert.True(rcRename.IsSuccess());
+
+ Assert.True(rcDir2.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, dir2Type);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rcDir1);
+ }
+
+ [Fact]
+ public void RenameDirectory_HasChildren_NewChildPathExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir1");
+ fs.CreateDirectory("/dir1/dirC");
+ fs.CreateFile("/dir1/file1", 0, CreateFileOptions.None);
+
+ Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
+
+ // Check that renamed structure exists
+ Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
+ Result rcDirC = fs.GetEntryType(out DirectoryEntryType dir1CType, "/dir2/dirC");
+ Result rcFile1 = fs.GetEntryType(out DirectoryEntryType file1Type, "/dir2/file1");
+
+ // Check that old structure doesn't exist
+ Result rcDir1 = fs.GetEntryType(out _, "/dir1");
+ Result rcDirCOld = fs.GetEntryType(out _, "/dir1/dirC");
+ Result rcFile1Old = fs.GetEntryType(out _, "/dir1/file1");
+
+ Assert.True(rcRename.IsSuccess());
+
+ Assert.True(rcDir2.IsSuccess());
+ Assert.True(rcDirC.IsSuccess());
+ Assert.True(rcFile1.IsSuccess());
+
+ Assert.Equal(DirectoryEntryType.Directory, dir2Type);
+ Assert.Equal(DirectoryEntryType.Directory, dir1CType);
+ Assert.Equal(DirectoryEntryType.File, file1Type);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rcDir1);
+ Assert.Equal(ResultFs.PathNotFound.Value, rcDirCOld);
+ Assert.Equal(ResultFs.PathNotFound.Value, rcFile1Old);
+ }
+
+ [Fact]
+ public void RenameDirectory_DestHasDifferentParentDirectory()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/parent1");
+ fs.CreateDirectory("/parent2");
+ fs.CreateDirectory("/parent1/dir1");
+
+ Result rcRename = fs.RenameDirectory("/parent1/dir1", "/parent2/dir2");
+
+ Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/parent2/dir2");
+ Result rcDir1 = fs.GetEntryType(out _, "/parent1/dir1");
+
+ Assert.True(rcRename.IsSuccess());
+
+ Assert.Equal(Result.Success, rcDir2);
+ Assert.True(rcDir2.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, dir2Type);
+
+ Assert.Equal(ResultFs.PathNotFound.Value, rcDir1);
+ }
+
+ [Fact]
+ public void RenameDirectory_DestExists_ReturnsPathAlreadyExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateDirectory("/dir1");
+ fs.CreateDirectory("/dir2");
+
+ Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
+
+ Result rcDir1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
+ Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
+
+ Assert.Equal(ResultFs.PathAlreadyExists.Value, rcRename);
+
+ Assert.True(rcDir1.IsSuccess());
+ Assert.True(rcDir2.IsSuccess());
+ Assert.Equal(DirectoryEntryType.Directory, dir1Type);
+ Assert.Equal(DirectoryEntryType.Directory, dir2Type);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameFile.cs
new file mode 100644
index 00000000..5106055a
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameFile.cs
@@ -0,0 +1,116 @@
+using LibHac.Fs;
+using Xunit;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ [Fact]
+ public void RenameFile_SameParentDirectory_EntryIsRenamed()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file1", 0, CreateFileOptions.None);
+
+ Assert.True(fs.RenameFile("/file1", "/file2").IsSuccess());
+
+ Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/file2").IsSuccess());
+ Result rc = fs.GetEntryType(out _, "/file1");
+
+ Assert.Equal(DirectoryEntryType.File, type);
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+ [Fact]
+ public void RenameFile_DifferentParentDirectory_EntryIsRenamed()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file1", 0, CreateFileOptions.None);
+ fs.CreateDirectory("/dir");
+
+ Assert.True(fs.RenameFile("/file1", "/dir/file2").IsSuccess());
+
+ Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/dir/file2").IsSuccess());
+ Result rc = fs.GetEntryType(out _, "/file1");
+
+ Assert.Equal(DirectoryEntryType.File, type);
+ Assert.Equal(ResultFs.PathNotFound.Value, rc);
+ }
+
+ [Fact]
+ public void RenameFile_DestExistsAsFile_ReturnsPathAlreadyExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file1", 0, CreateFileOptions.None);
+ fs.CreateFile("/file2", 0, CreateFileOptions.None);
+
+ Result rc = fs.RenameFile("/file1", "/file2");
+
+ Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
+ }
+
+ [Fact]
+ public void RenameFile_DestExistsAsDirectory_ReturnsPathAlreadyExists()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", 0, CreateFileOptions.None);
+ fs.CreateDirectory("/dir");
+
+ Result rc = fs.RenameFile("/file", "/dir");
+
+ Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
+ }
+
+ [Fact]
+ public void RenameFile_DestExistsAsFile_FileSizesDoNotChange()
+ {
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file1", 54321, CreateFileOptions.None);
+ fs.CreateFile("/file2", 12345, CreateFileOptions.None);
+
+ fs.RenameFile("/file1", "/file2");
+
+ Assert.True(fs.OpenFile(out IFile file1, "/file1", OpenMode.Read).IsSuccess());
+ Assert.True(fs.OpenFile(out IFile file2, "/file2", OpenMode.Read).IsSuccess());
+
+ using (file1)
+ using (file2)
+ {
+ Assert.True(file1.GetSize(out long file1Size).IsSuccess());
+ Assert.True(file2.GetSize(out long file2Size).IsSuccess());
+
+ Assert.Equal(54321, file1Size);
+ Assert.Equal(12345, file2Size);
+ }
+ }
+
+ [Fact]
+ public void RenameFile_DataIsUnmodified()
+ {
+ var data = new byte[] { 7, 4, 1, 0, 8, 5, 2, 9, 6, 3 };
+
+ IFileSystem fs = CreateFileSystem();
+
+ fs.CreateFile("/file", data.Length, CreateFileOptions.None);
+
+ fs.OpenFile(out IFile file, "/file", OpenMode.Write);
+ file.Write(0, data, WriteOption.None);
+ file.Dispose();
+
+ fs.RenameFile("/file", "/renamed");
+
+ var readData = new byte[data.Length];
+
+ fs.OpenFile(out file, "/renamed", OpenMode.Read);
+ Result rc = file.Read(out long bytesRead, 0, readData, ReadOption.None);
+ file.Dispose();
+
+ Assert.True(rc.IsSuccess());
+ Assert.Equal(data.Length, bytesRead);
+ Assert.Equal(data, readData);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.cs
new file mode 100644
index 00000000..a5f76787
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.cs
@@ -0,0 +1,9 @@
+using LibHac.Fs;
+
+namespace LibHac.Tests.Fs.IFileSystemTestBase
+{
+ public abstract partial class IFileSystemTests
+ {
+ protected abstract IFileSystem CreateFileSystem();
+ }
+}
diff --git a/tests/LibHac.Tests/Fs/InMemoryFileSystemTests.cs b/tests/LibHac.Tests/Fs/InMemoryFileSystemTests.cs
new file mode 100644
index 00000000..c4170dea
--- /dev/null
+++ b/tests/LibHac.Tests/Fs/InMemoryFileSystemTests.cs
@@ -0,0 +1,18 @@
+using LibHac.Fs;
+using LibHac.Tests.Fs.IFileSystemTestBase;
+
+namespace LibHac.Tests.Fs
+{
+ public class InMemoryFileSystemTests : IAttributeFileSystemTests
+ {
+ protected override IFileSystem CreateFileSystem()
+ {
+ return new InMemoryFileSystem();
+ }
+
+ protected override IAttributeFileSystem CreateAttributeFileSystem()
+ {
+ return new InMemoryFileSystem();
+ }
+ }
+}
diff --git a/tests/LibHac.Tests/InMemoryFileSystemTests.cs b/tests/LibHac.Tests/InMemoryFileSystemTests.cs
deleted file mode 100644
index 25784c50..00000000
--- a/tests/LibHac.Tests/InMemoryFileSystemTests.cs
+++ /dev/null
@@ -1,654 +0,0 @@
-using System;
-using LibHac.Common;
-using LibHac.Fs;
-using Xunit;
-
-namespace LibHac.Tests
-{
- public class InMemoryFileSystemTests
- {
- private IAttributeFileSystem GetFileSystem()
- {
- return new InMemoryFileSystem();
- }
-
- [Fact]
- public void CreateFileWithNoParentDirectory()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- Result rc = fs.CreateFile("/dir/file", 0, CreateFileOptions.None);
-
- Assert.Equal(ResultFs.PathNotFound.Value, rc);
- }
-
- [Fact]
- public void RootDirectoryHasCorrectEntryType()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- Result rc = fs.GetEntryType(out DirectoryEntryType type, "/");
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, type);
- }
-
- [Fact]
- public void CreatedFileHasCorrectSize()
- {
- const long expectedSize = 12345;
-
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file", expectedSize, CreateFileOptions.None);
-
- fs.OpenFile(out IFile file, "/file", OpenMode.Read);
- Result rc = file.GetSize(out long fileSize);
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(expectedSize, fileSize);
- }
-
- [Fact]
- public void ReadDataWrittenToFileAfterReopening()
- {
- var data = new byte[] { 7, 4, 1, 0, 8, 5, 2, 9, 6, 3 };
-
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file", data.Length, CreateFileOptions.None);
-
- fs.OpenFile(out IFile file, "/file", OpenMode.Write);
- file.Write(0, data, WriteOption.None);
- file.Dispose();
-
- var readData = new byte[data.Length];
-
- fs.OpenFile(out file, "/file", OpenMode.Read);
- Result rc = file.Read(out long bytesRead, 0, readData, ReadOption.None);
- file.Dispose();
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(data.Length, bytesRead);
- Assert.Equal(data, readData);
- }
-
- [Fact]
- public void ReadDataWrittenToFileAfterRenaming()
- {
- var data = new byte[] { 7, 4, 1, 0, 8, 5, 2, 9, 6, 3 };
-
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file", data.Length, CreateFileOptions.None);
-
- fs.OpenFile(out IFile file, "/file", OpenMode.Write);
- file.Write(0, data, WriteOption.None);
- file.Dispose();
-
- fs.RenameFile("/file", "/renamed");
-
- var readData = new byte[data.Length];
-
- fs.OpenFile(out file, "/renamed", OpenMode.Read);
- Result rc = file.Read(out long bytesRead, 0, readData, ReadOption.None);
- file.Dispose();
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(data.Length, bytesRead);
- Assert.Equal(data, readData);
- }
-
- [Fact]
- public void OpenFileAsDirectory()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file", 0, CreateFileOptions.None);
-
- Result rc = fs.OpenDirectory(out _, "/file", OpenDirectoryMode.All);
-
- Assert.Equal(ResultFs.PathNotFound.Value, rc);
- }
-
- [Fact]
- public void OpenDirectoryAsFile()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir");
-
- Result rc = fs.OpenFile(out _, "/dir", OpenMode.All);
-
- Assert.Equal(ResultFs.PathNotFound.Value, rc);
- }
-
- [Fact]
- public void DeleteNonexistentFile()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- Result rc = fs.DeleteFile("/file");
- Assert.Equal(ResultFs.PathNotFound.Value, rc);
- }
-
- [Fact]
- public void DeleteNonexistentDirectory()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- Result rc = fs.DeleteDirectory("/dir");
- Assert.Equal(ResultFs.PathNotFound.Value, rc);
- }
-
- [Fact]
- public void DeleteFile()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file", 0, CreateFileOptions.None);
-
- Result rcDelete = fs.DeleteFile("/file");
- Result rcEntry = fs.GetEntryType(out _, "/file");
-
- Assert.True(rcDelete.IsSuccess());
- Assert.Equal(ResultFs.PathNotFound.Value, rcEntry);
- }
-
- [Fact]
- public void DeleteFileWithSiblingA()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file1", 0, CreateFileOptions.None);
- fs.CreateFile("/file2", 0, CreateFileOptions.None);
-
- Result rcDelete = fs.DeleteFile("/file2");
- Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1");
- Result rcEntry2 = fs.GetEntryType(out _, "/file2");
-
- Assert.True(rcDelete.IsSuccess());
- Assert.True(rcEntry1.IsSuccess());
- Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
-
- Assert.Equal(DirectoryEntryType.File, dir1Type);
- }
-
- [Fact]
- public void DeleteFileWithSiblingB()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file2", 0, CreateFileOptions.None);
- fs.CreateFile("/file1", 0, CreateFileOptions.None);
-
- Result rcDelete = fs.DeleteFile("/file2");
- Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1");
- Result rcEntry2 = fs.GetEntryType(out _, "/file2");
-
- Assert.True(rcDelete.IsSuccess());
- Assert.True(rcEntry1.IsSuccess());
- Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
-
- Assert.Equal(DirectoryEntryType.File, dir1Type);
- }
-
- [Fact]
- public void DeleteDirectory()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir");
-
- Result rcDelete = fs.DeleteDirectory("/dir");
- Result rcEntry = fs.GetEntryType(out _, "/dir");
-
- Assert.True(rcDelete.IsSuccess());
- Assert.Equal(ResultFs.PathNotFound.Value, rcEntry);
- }
-
- [Fact]
- public void DeleteDirectoryWithSiblingA()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir1");
- fs.CreateDirectory("/dir2");
-
- Result rcDelete = fs.DeleteDirectory("/dir2");
- Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
- Result rcEntry2 = fs.GetEntryType(out _, "/dir2");
-
- Assert.True(rcDelete.IsSuccess());
- Assert.True(rcEntry1.IsSuccess());
- Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
-
- Assert.Equal(DirectoryEntryType.Directory, dir1Type);
- }
-
- [Fact]
- public void DeleteDirectoryWithSiblingB()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir2");
- fs.CreateDirectory("/dir1");
-
- Result rcDelete = fs.DeleteDirectory("/dir2");
- Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
- Result rcEntry2 = fs.GetEntryType(out _, "/dir2");
-
- Assert.True(rcDelete.IsSuccess());
- Assert.True(rcEntry1.IsSuccess());
- Assert.Equal(ResultFs.PathNotFound.Value, rcEntry2);
-
- Assert.Equal(DirectoryEntryType.Directory, dir1Type);
- }
-
- [Fact]
- public void DeleteDirectoryWithChildren()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir");
- fs.CreateFile("/dir/file", 0, CreateFileOptions.None);
-
- Result rc = fs.DeleteDirectory("/dir");
-
- Assert.Equal(ResultFs.DirectoryNotEmpty.Value, rc);
- }
-
- [Fact]
- public void DeleteDirectoryRecursively()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir");
- fs.CreateDirectory("/dir/dir2");
- fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
-
- Result rcDelete = fs.DeleteDirectoryRecursively("/dir");
-
- Result rcDir1Type = fs.GetEntryType(out _, "/dir");
- Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2");
- Result rcFileType = fs.GetEntryType(out _, "/dir/file1");
-
- Assert.True(rcDelete.IsSuccess());
-
- Assert.Equal(ResultFs.PathNotFound.Value, rcDir1Type);
- Assert.Equal(ResultFs.PathNotFound.Value, rcDir2Type);
- Assert.Equal(ResultFs.PathNotFound.Value, rcFileType);
- }
-
- [Fact]
- public void CleanDirectoryRecursively()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir");
- fs.CreateDirectory("/dir/dir2");
- fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
-
- Result rcDelete = fs.CleanDirectoryRecursively("/dir");
-
- Result rcDir1Type = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir");
- Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2");
- Result rcFileType = fs.GetEntryType(out _, "/dir/file1");
-
- Assert.True(rcDelete.IsSuccess());
-
- Assert.True(rcDir1Type.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, dir1Type);
-
- Assert.Equal(ResultFs.PathNotFound.Value, rcDir2Type);
- Assert.Equal(ResultFs.PathNotFound.Value, rcFileType);
- }
-
- [Fact]
- public void CreateFile()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file", 0, CreateFileOptions.None);
- Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file");
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(DirectoryEntryType.File, type);
- }
-
- [Fact]
- public void CreateFileWithTrailingSlash()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file/", 0, CreateFileOptions.None);
- Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file/");
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(DirectoryEntryType.File, type);
- }
-
- [Fact]
- public void CreateDirectory()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir");
- Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir");
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, type);
- }
-
- [Fact]
- public void CreateDirectoryWithTrailingSlash()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir/");
- Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir/");
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, type);
- }
-
- [Fact]
- public void CreateMultipleDirectories()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir1");
- fs.CreateDirectory("/dir2");
- Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1");
- Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2");
-
- Assert.True(rc1.IsSuccess());
- Assert.True(rc2.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, type1);
- Assert.Equal(DirectoryEntryType.Directory, type2);
- }
-
- [Fact]
- public void CreateMultipleNestedDirectories()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir1");
- fs.CreateDirectory("/dir2");
-
- fs.CreateDirectory("/dir1/dir1a");
- fs.CreateDirectory("/dir2/dir2a");
- Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/dir1a");
- Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/dir2a");
-
- Assert.True(rc1.IsSuccess());
- Assert.True(rc2.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, type1);
- Assert.Equal(DirectoryEntryType.Directory, type2);
- }
-
- [Fact]
- public void CreateDirectoryWithAttribute()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir1", NxFileAttributes.None);
- fs.CreateDirectory("/dir2", NxFileAttributes.Archive);
-
- Result rc1 = fs.GetFileAttributes("/dir1", out NxFileAttributes type1);
- Result rc2 = fs.GetFileAttributes("/dir2", out NxFileAttributes type2);
-
- Assert.True(rc1.IsSuccess());
- Assert.True(rc2.IsSuccess());
-
- Assert.Equal(NxFileAttributes.Directory, type1);
- Assert.Equal(NxFileAttributes.Directory | NxFileAttributes.Archive, type2);
- }
-
- [Fact]
- public void RenameFile()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file1", 12345, CreateFileOptions.None);
-
- Result rcRename = fs.RenameFile("/file1", "/file2");
-
- Result rcOpen = fs.OpenFile(out IFile file, "/file2", OpenMode.All);
- Result rcSize = file.GetSize(out long fileSize);
-
- Result rcOldType = fs.GetEntryType(out _, "/file1");
-
- Assert.True(rcRename.IsSuccess());
- Assert.True(rcOpen.IsSuccess());
- Assert.True(rcSize.IsSuccess());
-
- Assert.Equal(12345, fileSize);
- Assert.Equal(ResultFs.PathNotFound.Value, rcOldType);
- }
-
- [Fact]
- public void RenameFileWhenDestExists()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateFile("/file1", 12345, CreateFileOptions.None);
- fs.CreateFile("/file2", 54321, CreateFileOptions.None);
-
- Result rcRename = fs.RenameFile("/file1", "/file2");
-
- Result rcFile1 = fs.GetEntryType(out DirectoryEntryType file1Type, "/file1");
- Result rcFile2 = fs.GetEntryType(out DirectoryEntryType file2Type, "/file2");
-
- Assert.Equal(ResultFs.PathAlreadyExists.Value, rcRename);
-
- Assert.True(rcFile1.IsSuccess());
- Assert.True(rcFile2.IsSuccess());
- Assert.Equal(DirectoryEntryType.File, file1Type);
- Assert.Equal(DirectoryEntryType.File, file2Type);
- }
-
- [Fact]
- public void RenameDirectory()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir1");
- Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
-
- Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
- Result rcDir1 = fs.GetEntryType(out _, "/dir1");
-
- Assert.True(rcRename.IsSuccess());
-
- Assert.True(rcDir2.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, dir2Type);
-
- Assert.Equal(ResultFs.PathNotFound.Value, rcDir1);
- }
-
- [Fact]
- public void RenameDirectoryWithChildren()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir1");
- fs.CreateDirectory("/dir1/dirC");
- fs.CreateFile("/dir1/file1", 0, CreateFileOptions.None);
-
- Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
-
- // Check that renamed structure exists
- Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
- Result rcDirC = fs.GetEntryType(out DirectoryEntryType dir1CType, "/dir2/dirC");
- Result rcFile1 = fs.GetEntryType(out DirectoryEntryType file1Type, "/dir2/file1");
-
- // Check that old structure doesn't exist
- Result rcDir1 = fs.GetEntryType(out _, "/dir1");
- Result rcDirCOld = fs.GetEntryType(out _, "/dir1/dirC");
- Result rcFile1Old = fs.GetEntryType(out _, "/dir1/file1");
-
- Assert.True(rcRename.IsSuccess());
-
- Assert.True(rcDir2.IsSuccess());
- Assert.True(rcDirC.IsSuccess());
- Assert.True(rcFile1.IsSuccess());
-
- Assert.Equal(DirectoryEntryType.Directory, dir2Type);
- Assert.Equal(DirectoryEntryType.Directory, dir1CType);
- Assert.Equal(DirectoryEntryType.File, file1Type);
-
- Assert.Equal(ResultFs.PathNotFound.Value, rcDir1);
- Assert.Equal(ResultFs.PathNotFound.Value, rcDirCOld);
- Assert.Equal(ResultFs.PathNotFound.Value, rcFile1Old);
- }
-
- [Fact]
- public void RenameDirectoryToDifferentParent()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/parent1");
- fs.CreateDirectory("/parent2");
- fs.CreateDirectory("/parent1/dir1");
-
- Result rcRename = fs.RenameDirectory("/parent1/dir1", "/parent2/dir2");
-
- Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/parent2/dir2");
- Result rcDir1 = fs.GetEntryType(out _, "/parent1/dir1");
-
- Assert.True(rcRename.IsSuccess());
-
- Assert.Equal(Result.Success, rcDir2);
- Assert.True(rcDir2.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, dir2Type);
-
- Assert.Equal(ResultFs.PathNotFound.Value, rcDir1);
- }
-
- [Fact]
- public void RenameDirectoryWhenDestExists()
- {
- IAttributeFileSystem fs = GetFileSystem();
-
- fs.CreateDirectory("/dir1");
- fs.CreateDirectory("/dir2");
-
- Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
-
- Result rcDir1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
- Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
-
- Assert.Equal(ResultFs.PathAlreadyExists.Value, rcRename);
-
- Assert.True(rcDir1.IsSuccess());
- Assert.True(rcDir2.IsSuccess());
- Assert.Equal(DirectoryEntryType.Directory, dir1Type);
- Assert.Equal(DirectoryEntryType.Directory, dir2Type);
- }
-
- [Fact]
- public void SetFileSize()
- {
- IAttributeFileSystem fs = GetFileSystem();
- fs.CreateFile("/file", 0, CreateFileOptions.None);
-
- fs.OpenFile(out IFile file, "/file", OpenMode.All);
- Result rc = file.SetSize(54321);
- file.Dispose();
-
- fs.OpenFile(out file, "/file", OpenMode.All);
- file.GetSize(out long fileSize);
- file.Dispose();
-
- Assert.True(rc.IsSuccess());
- Assert.Equal(54321, fileSize);
- }
-
- [Fact]
- public void SetFileAttributes()
- {
- IAttributeFileSystem fs = GetFileSystem();
- fs.CreateFile("/file", 0, CreateFileOptions.None);
-
- Result rcSet = fs.SetFileAttributes("/file", NxFileAttributes.Archive);
- Result rcGet = fs.GetFileAttributes("/file", out NxFileAttributes attributes);
-
- Assert.True(rcSet.IsSuccess());
- Assert.True(rcGet.IsSuccess());
- Assert.Equal(NxFileAttributes.Archive, attributes);
- }
-
- [Fact]
- public void IterateDirectory()
- {
- IAttributeFileSystem fs = GetFileSystem();
- fs.CreateDirectory("/dir");
- fs.CreateDirectory("/dir/dir1");
- fs.CreateFile("/dir/dir1/file1", 0, CreateFileOptions.None);
- fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
- fs.CreateFile("/dir/file2", 0, CreateFileOptions.None);
-
- Result rc = fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All);
- Assert.True(rc.IsSuccess());
-
- var entry1 = new DirectoryEntry();
- var entry2 = new DirectoryEntry();
- var entry3 = new DirectoryEntry();
- var entry4 = new DirectoryEntry();
-
- Assert.True(dir.Read(out long entriesRead1, SpanHelpers.AsSpan(ref entry1)).IsSuccess());
- Assert.True(dir.Read(out long entriesRead2, SpanHelpers.AsSpan(ref entry2)).IsSuccess());
- Assert.True(dir.Read(out long entriesRead3, SpanHelpers.AsSpan(ref entry3)).IsSuccess());
- Assert.True(dir.Read(out long entriesRead4, SpanHelpers.AsSpan(ref entry4)).IsSuccess());
-
- Assert.Equal(1, entriesRead1);
- Assert.Equal(1, entriesRead2);
- Assert.Equal(1, entriesRead3);
- Assert.Equal(0, entriesRead4);
-
- bool dir1Read = false;
- bool file1Read = false;
- bool file2Read = false;
-
- // Entries are not guaranteed to be in any particular order
- CheckEntry(ref entry1);
- CheckEntry(ref entry2);
- CheckEntry(ref entry3);
-
- Assert.True(dir1Read);
- Assert.True(file1Read);
- Assert.True(file2Read);
-
- void CheckEntry(ref DirectoryEntry entry)
- {
- switch (StringUtils.Utf8ZToString(entry.Name))
- {
- case "dir1":
- Assert.False(dir1Read);
- Assert.Equal(DirectoryEntryType.Directory, entry.Type);
-
- dir1Read = true;
- break;
-
- case "file1":
- Assert.False(file1Read);
- Assert.Equal(DirectoryEntryType.File, entry.Type);
-
- file1Read = true;
- break;
-
- case "file2":
- Assert.False(file2Read);
- Assert.Equal(DirectoryEntryType.File, entry.Type);
-
- file2Read = true;
- break;
-
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- }
- }
-}
diff --git a/tests/LibHac.Tests/LibHac.Tests.csproj b/tests/LibHac.Tests/LibHac.Tests.csproj
index 3ebc86d8..99b3149c 100644
--- a/tests/LibHac.Tests/LibHac.Tests.csproj
+++ b/tests/LibHac.Tests/LibHac.Tests.csproj
@@ -16,6 +16,10 @@
+
+
+
+
diff --git a/tests/LibHac.Tests/LibHac.Tests.csproj.DotSettings b/tests/LibHac.Tests/LibHac.Tests.csproj.DotSettings
new file mode 100644
index 00000000..19c37353
--- /dev/null
+++ b/tests/LibHac.Tests/LibHac.Tests.csproj.DotSettings
@@ -0,0 +1,2 @@
+
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="I" Suffix="" Style="AaBb" /></Policy>
\ No newline at end of file