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