diff --git a/.gitignore b/.gitignore index 15d1cf5..a91deb9 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ # Mono auto generated files mono_crash.* +.mono/ # Build results [Dd]ebug/ diff --git a/Cyclotron.Tests/Integration/FileSystemAdapter/FileSystemAdapterIntegrationTests.cs b/Cyclotron.Tests/Integration/FileSystemAdapter/FileSystemAdapterIntegrationTests.cs index 58b53c8..9be1f32 100644 --- a/Cyclotron.Tests/Integration/FileSystemAdapter/FileSystemAdapterIntegrationTests.cs +++ b/Cyclotron.Tests/Integration/FileSystemAdapter/FileSystemAdapterIntegrationTests.cs @@ -4,6 +4,7 @@ using Cyclotron.FileSystemAdapter.WinUI; using Cyclotron.Tests.Integration.Fixtures; using AwesomeAssertions; +using System.Text; using WinStorage = Windows.Storage; namespace Cyclotron.Tests.Integration.FileSystemAdapter; @@ -188,6 +189,18 @@ public async Task FolderHandler_GetParentAsync_ReturnsParent() parent.Path.Should().Be(_fixture.RootPath); } + [Test] + public async Task FolderHandler_GetItemsAsync_ContainsFilesAndFolders() + { + await _folderHandler.CreateFileAsync(_rootFolder, "mix.txt"); + await _folderHandler.CreateFolderAsync(_rootFolder, "mixdir"); + + var items = await _folderHandler.GetItemsAsync(_rootFolder); + + items.Should().Contain(item => item is IFile, "expected at least one IFile in items"); + items.Should().Contain(item => item is IFolder, "expected at least one IFolder in items"); + } + #endregion #region WinUIFolderHandler - Rename & Delete @@ -420,6 +433,18 @@ public async Task FileHandler_OpenAsync_WithStorageOptions_DoesNotThrow() await act.Should().NotThrowAsync(); } + [Test] + public async Task FileHandler_OpenAsync_ReadWrite_DoesNotThrow() + { + var path = _fixture.GetTempFilePath("rw_open.txt"); + await File.WriteAllTextAsync(path, "content"); + var file = await _fileHandler.GetFileFromPathAsync(path); + + var act = async () => await _fileHandler.OpenAsync(file, FileAccessMode.ReadWrite); + + await act.Should().NotThrowAsync(); + } + #endregion #region FileExtensions & FolderExtensions (via WinUI objects) @@ -753,5 +778,588 @@ public async Task StorageFolder_AsIFolder_ReturnsWinUIFolder() } #endregion + + #region Error Cases - Not Found + + [Test] + public async Task FolderHandler_GetFileAsync_ThrowsFileNotFoundException_WhenFileNotFound() + { + var act = async () => await _folderHandler.GetFileAsync(_rootFolder, "nonexistent.txt"); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FolderHandler_GetFolderAsync_ThrowsFileNotFoundException_WhenSubfolderNotFound() + { + var act = async () => await _folderHandler.GetFolderAsync(_rootFolder, "nonexistent"); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FileHandler_GetFileFromPathAsync_ThrowsFileNotFoundException_WhenPathNotFound() + { + var nonexistentPath = Path.Combine( + Path.GetTempPath(), "Cyclotron.Tests", "nonexistent", Guid.NewGuid().ToString(), "file.txt"); + + var act = async () => await _fileHandler.GetFileFromPathAsync(nonexistentPath); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FolderHandler_GetFolderFromPathAsync_ThrowsFileNotFoundException_WhenPathNotFound() + { + var nonexistentPath = Path.Combine( + Path.GetTempPath(), "Cyclotron.Tests", "nonexistent", Guid.NewGuid().ToString()); + + var act = async () => await _folderHandler.GetFolderFromPathAsync(nonexistentPath); + + await act.Should().ThrowAsync(); + } + + #endregion + + #region Collision Option - FailIfExists + + [Test] + public async Task FolderHandler_CreateFileAsync_WithFailIfExists_ThrowsException_WhenFileAlreadyExists() + { + await _folderHandler.CreateFileAsync(_rootFolder, "fail.txt"); + + var act = async () => await _folderHandler.CreateFileAsync( + _rootFolder, "fail.txt", CreationCollisionOption.FailIfExists); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FolderHandler_CreateFolderAsync_WithFailIfExists_ThrowsException_WhenFolderAlreadyExists() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "failsub"); + + var act = async () => await _folderHandler.CreateFolderAsync( + _rootFolder, "failsub", CreationCollisionOption.FailIfExists); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FileHandler_RenameAsync_WithFailIfExists_ThrowsException_WhenNameExists() + { + await _folderHandler.CreateFileAsync(_rootFolder, "ren_src.txt"); + await _folderHandler.CreateFileAsync(_rootFolder, "ren_dst.txt"); + var file = await _folderHandler.GetFileAsync(_rootFolder, "ren_src.txt"); + + var act = async () => await _fileHandler.RenameAsync(file, "ren_dst.txt", NameCollisionOption.FailIfExists); + + await act.Should().ThrowAsync(); + } + + #endregion + + #region Collision Option - GenerateUniqueName + + [Test] + public async Task FolderHandler_CreateFileAsync_WithGenerateUniqueName_CreatesBothFiles() + { + await _folderHandler.CreateFileAsync(_rootFolder, "dup.txt"); + + var act = async () => await _folderHandler.CreateFileAsync( + _rootFolder, "dup.txt", CreationCollisionOption.GenerateUniqueName); + + await act.Should().NotThrowAsync(); + var files = await _folderHandler.GetFileAsync(_rootFolder); + files.Should().HaveCountGreaterThanOrEqualTo(2, + "both the original and the uniquely-named duplicate should exist"); + } + + [Test] + public async Task FolderHandler_CreateFolderAsync_WithGenerateUniqueName_CreatesBothFolders() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "dupdir"); + + var act = async () => await _folderHandler.CreateFolderAsync( + _rootFolder, "dupdir", CreationCollisionOption.GenerateUniqueName); + + await act.Should().NotThrowAsync(); + var folders = await _folderHandler.GetFoldersAsync(_rootFolder); + folders.Should().HaveCountGreaterThanOrEqualTo(2, + "both the original and the uniquely-named duplicate should exist"); + } + + #endregion + + #region File Content Preservation + + [Test] + public async Task FileHandler_CopyAsync_PreservesFileContent() + { + var srcPath = _fixture.GetTempFilePath("src_content.txt"); + await File.WriteAllTextAsync(srcPath, "source content"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "dest_content"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "dest_content"); + + await _fileHandler.CopyAsync(src, destFolder, "copied_content.txt", NameCollisionOption.ReplaceExisting); + + var result = await File.ReadAllTextAsync(Path.Combine(_fixture.RootPath, "dest_content", "copied_content.txt")); + result.Should().Be("source content"); + } + + [Test] + public async Task FileHandler_CopyAndReplaceAsync_CopiesSourceContentToDest() + { + var srcPath = _fixture.GetTempFilePath("cpr_src.txt"); + var dstPath = _fixture.GetTempFilePath("cpr_dst.txt"); + await File.WriteAllTextAsync(srcPath, "original src"); + await File.WriteAllTextAsync(dstPath, "original dst"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + var dst = await _fileHandler.GetFileFromPathAsync(dstPath); + + await _fileHandler.CopyAndReplaceAsync(src, dst); + + var dstContent = await File.ReadAllTextAsync(dstPath); + dstContent.Should().Be("original src"); + var srcContent = await File.ReadAllTextAsync(srcPath); + srcContent.Should().Be("original src"); + } + + [Test] + public async Task FileHandler_MoveAsync_PreservesFileContent() + { + var srcPath = _fixture.GetTempFilePath("mv_content.txt"); + await File.WriteAllTextAsync(srcPath, "move me"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "mv_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "mv_dest"); + + await _fileHandler.MoveAsync(src, destFolder); + + var result = await File.ReadAllTextAsync(Path.Combine(_fixture.RootPath, "mv_dest", "mv_content.txt")); + result.Should().Be("move me"); + File.Exists(srcPath).Should().BeFalse(); + } + + [Test] + public async Task FileHandler_MoveAsync_WithName_PreservesContent() + { + var srcPath = _fixture.GetTempFilePath("mv_nm_src.txt"); + await File.WriteAllTextAsync(srcPath, "named move"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "mv_nm_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "mv_nm_dest"); + + await _fileHandler.MoveAsync(src, destFolder, "mv_nm_moved.txt"); + + var result = await File.ReadAllTextAsync(Path.Combine(_fixture.RootPath, "mv_nm_dest", "mv_nm_moved.txt")); + result.Should().Be("named move"); + } + + [Test] + public async Task FileHandler_MoveAndReplaceAsync_CopiesSourceContentToDest() + { + var srcPath = _fixture.GetTempFilePath("mar_src.txt"); + var dstPath = _fixture.GetTempFilePath("mar_dst.txt"); + await File.WriteAllTextAsync(srcPath, "src to move"); + await File.WriteAllTextAsync(dstPath, "dest old"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + var dst = await _fileHandler.GetFileFromPathAsync(dstPath); + + await _fileHandler.MoveAndReplaceAsync(src, dst); + + var dstContent = await File.ReadAllTextAsync(dstPath); + dstContent.Should().Be("src to move"); + File.Exists(srcPath).Should().BeFalse(); + } + + #endregion + + #region Copy Collision Options + + [Test] + public async Task FileHandler_CopyAsync_WithFailIfExists_ThrowsIOException() + { + var srcPath = _fixture.GetTempFilePath("cfe_src.txt"); + await File.WriteAllTextAsync(srcPath, "content"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "cfe_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "cfe_dest"); + await _folderHandler.CreateFileAsync(destFolder, "cfe_copy.txt"); + + var act = async () => await _fileHandler.CopyAsync(src, destFolder, "cfe_copy.txt", NameCollisionOption.FailIfExists); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FileHandler_CopyAsync_WithGenerateUniqueName_CreatesBothFiles() + { + var srcPath = _fixture.GetTempFilePath("cgu_src.txt"); + await File.WriteAllTextAsync(srcPath, "orig"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "cgu_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "cgu_dest"); + await _folderHandler.CreateFileAsync(destFolder, "cgu_copy.txt"); + + var act = async () => await _fileHandler.CopyAsync(src, destFolder, "cgu_copy.txt", NameCollisionOption.GenerateUniqueName); + + await act.Should().NotThrowAsync(); + var files = await _folderHandler.GetFileAsync(destFolder); + files.Should().HaveCountGreaterThanOrEqualTo(2, + "both the original and the uniquely-named copy should exist"); + } + + [Test] + public async Task FileHandler_CopyAsync_WithReplaceExisting_ReplacesFileContent() + { + var srcPath = _fixture.GetTempFilePath("cre_src.txt"); + await File.WriteAllTextAsync(srcPath, "new content"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "cre_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "cre_dest"); + var existingDestPath = Path.Combine(_fixture.RootPath, "cre_dest", "cre_copy.txt"); + await File.WriteAllTextAsync(existingDestPath, "old content"); + + await _fileHandler.CopyAsync(src, destFolder, "cre_copy.txt", NameCollisionOption.ReplaceExisting); + + var result = await File.ReadAllTextAsync(existingDestPath); + result.Should().Be("new content"); + } + + #endregion + + #region Move Collision Options + + [Test] + public async Task FileHandler_MoveAsync_WithNameAndOption_FailIfExists_ThrowsIOException() + { + var srcPath = _fixture.GetTempFilePath("mfe_src.txt"); + await File.WriteAllTextAsync(srcPath, "src"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "mfe_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "mfe_dest"); + await _folderHandler.CreateFileAsync(destFolder, "mfe_moved.txt"); + + var act = async () => await _fileHandler.MoveAsync(src, destFolder, "mfe_moved.txt", NameCollisionOption.FailIfExists); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FileHandler_MoveAsync_WithNameAndOption_GenerateUniqueName_CreatesUniqueFile() + { + var srcPath = _fixture.GetTempFilePath("mgu_src.txt"); + await File.WriteAllTextAsync(srcPath, "src"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "mgu_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "mgu_dest"); + await _folderHandler.CreateFileAsync(destFolder, "mgu_moved.txt"); + + var act = async () => await _fileHandler.MoveAsync(src, destFolder, "mgu_moved.txt", NameCollisionOption.GenerateUniqueName); + + await act.Should().NotThrowAsync(); + var files = await _folderHandler.GetFileAsync(destFolder); + files.Should().HaveCountGreaterThanOrEqualTo(2, + "both the original existing file and the uniquely-named moved file should exist"); + } + + [Test] + public async Task FileHandler_MoveAsync_WithNameAndOption_ReplaceExisting_MovesAndReplaces() + { + var srcPath = _fixture.GetTempFilePath("mre_src.txt"); + await File.WriteAllTextAsync(srcPath, "new src"); + var src = await _fileHandler.GetFileFromPathAsync(srcPath); + await _folderHandler.CreateFolderAsync(_rootFolder, "mre_dest"); + var destFolder = await _folderHandler.GetFolderAsync(_rootFolder, "mre_dest"); + var existingDestPath = Path.Combine(_fixture.RootPath, "mre_dest", "mre_moved.txt"); + await File.WriteAllTextAsync(existingDestPath, "old content"); + + await _fileHandler.MoveAsync(src, destFolder, "mre_moved.txt", NameCollisionOption.ReplaceExisting); + + var result = await File.ReadAllTextAsync(existingDestPath); + result.Should().Be("new src"); + File.Exists(srcPath).Should().BeFalse(); + } + + #endregion + + #region Rename Collision Options + + [Test] + public async Task FileHandler_RenameAsync_WithReplaceExisting_ReplacesTargetFile() + { + await _folderHandler.CreateFileAsync(_rootFolder, "ren_rep_src.txt"); + await _folderHandler.CreateFileAsync(_rootFolder, "ren_rep_dst.txt"); + var srcFile = await _folderHandler.GetFileAsync(_rootFolder, "ren_rep_src.txt"); + + var act = async () => await _fileHandler.RenameAsync(srcFile, "ren_rep_dst.txt", NameCollisionOption.ReplaceExisting); + + await act.Should().NotThrowAsync(); + File.Exists(Path.Combine(_fixture.RootPath, "ren_rep_dst.txt")).Should().BeTrue(); + File.Exists(Path.Combine(_fixture.RootPath, "ren_rep_src.txt")).Should().BeFalse(); + } + + [Test] + public async Task FolderHandler_RenameAsync_WithFailIfExists_ThrowsIOException_WhenTargetNameExists() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "fren_orig"); + await _folderHandler.CreateFolderAsync(_rootFolder, "fren_target"); + var folder = await _folderHandler.GetFolderAsync(_rootFolder, "fren_orig"); + + var act = async () => await _folderHandler.RenameAsync(folder, "fren_target", NameCollisionOption.FailIfExists); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task FolderHandler_RenameAsync_WithReplaceExisting_ReplacesTarget() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "frep_orig"); + await _folderHandler.CreateFolderAsync(_rootFolder, "frep_target"); + var folder = await _folderHandler.GetFolderAsync(_rootFolder, "frep_orig"); + + var act = async () => await _folderHandler.RenameAsync(folder, "frep_target", NameCollisionOption.ReplaceExisting); + + await act.Should().NotThrowAsync(); + Directory.Exists(Path.Combine(_fixture.RootPath, "frep_orig")).Should().BeFalse(); + } + + #endregion + + #region CreateFile / CreateFolder Collision Semantics + + [Test] + public async Task FolderHandler_CreateFileAsync_WithReplaceExisting_TruncatesExistingFile() + { + var filePath = Path.Combine(_fixture.RootPath, "replace_me.txt"); + // Arrange: pre-create the file with content so there is something to replace + await File.WriteAllTextAsync(filePath, "old content"); + + await _folderHandler.CreateFileAsync(_rootFolder, "replace_me.txt", CreationCollisionOption.ReplaceExisting); + + var content = await File.ReadAllTextAsync(filePath); + content.Should().BeEmpty("ReplaceExisting should create a new empty file, discarding old content"); + } + + [Test] + public async Task FolderHandler_CreateFileAsync_WithOpenIfExists_DoesNotOverwriteExistingContent() + { + var filePath = Path.Combine(_fixture.RootPath, "open_if.txt"); + await File.WriteAllTextAsync(filePath, "keep me"); + + await _folderHandler.CreateFileAsync(_rootFolder, "open_if.txt", CreationCollisionOption.OpenIfExists); + + var content = await File.ReadAllTextAsync(filePath); + content.Should().Be("keep me", "OpenIfExists should open the existing file without truncating it"); + } + + [Test] + public async Task FolderHandler_CreateFolderAsync_WithReplaceExisting_ReplacesFolder() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "rep_dir"); + var innerPath = Path.Combine(_fixture.RootPath, "rep_dir", "inner.txt"); + // Arrange: add a file inside the folder so we can verify it is gone after replacement + await File.WriteAllTextAsync(innerPath, "inner content"); + + await _folderHandler.CreateFolderAsync(_rootFolder, "rep_dir", CreationCollisionOption.ReplaceExisting); + + Directory.Exists(Path.Combine(_fixture.RootPath, "rep_dir")).Should().BeTrue( + "the folder should be recreated after ReplaceExisting"); + File.Exists(innerPath).Should().BeFalse( + "the inner file should be gone because the folder was replaced with a new empty one"); + } + + [Test] + public async Task FolderHandler_CreateFolderAsync_WithOpenIfExists_ReturnsExistingFolder() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "oif_dir"); + var innerPath = Path.Combine(_fixture.RootPath, "oif_dir", "oif_file.txt"); + await File.WriteAllTextAsync(innerPath, "keep"); + + await _folderHandler.CreateFolderAsync(_rootFolder, "oif_dir", CreationCollisionOption.OpenIfExists); + + Directory.Exists(Path.Combine(_fixture.RootPath, "oif_dir")).Should().BeTrue( + "the existing folder should remain after OpenIfExists"); + } + + #endregion + + #region Return Value Precision + + [Test] + public async Task FolderHandler_GetFileAsync_ByName_HasCorrectPath() + { + await _folderHandler.CreateFileAsync(_rootFolder, "path_check.txt"); + + var file = await _folderHandler.GetFileAsync(_rootFolder, "path_check.txt"); + + file.Path.Should().Be(Path.Combine(_fixture.RootPath, "path_check.txt")); + file.FolderRelativeId.Should().NotBeNullOrEmpty(); + } + + [Test] + public async Task FolderHandler_GetFolderAsync_ByName_HasCorrectPath() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "path_dir"); + + var folder = await _folderHandler.GetFolderAsync(_rootFolder, "path_dir"); + + folder.Path.Should().Be(Path.Combine(_fixture.RootPath, "path_dir")); + folder.Name.Should().Be("path_dir"); + folder.FolderRelativeId.Should().NotBeNullOrEmpty(); + } + + [Test] + public async Task FolderHandler_GetFolderFromPathAsync_HasCorrectProperties() + { + var folder = await _folderHandler.GetFolderFromPathAsync(_fixture.RootPath); + + folder.Path.Should().Be(_fixture.RootPath); + folder.Name.Should().NotBeNullOrEmpty(); + folder.FolderRelativeId.Should().NotBeNullOrEmpty(); + } + + [Test] + public async Task FolderHandler_GetItemAsync_ForFile_ReturnsIFileType() + { + await _folderHandler.CreateFileAsync(_rootFolder, "typed_item.txt"); + + var item = await _folderHandler.GetItemAsync(_rootFolder, "typed_item.txt"); + + item.Should().BeAssignableTo(); + } + + [Test] + public async Task FolderHandler_GetItemAsync_ForFolder_ReturnsIFolderType() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "typed_dir"); + + var item = await _folderHandler.GetItemAsync(_rootFolder, "typed_dir"); + + item.Should().BeAssignableTo(); + } + + [Test] + public async Task FileHandler_GetFileFromPathAsync_HasCorrectFolderRelativeId() + { + var path = _fixture.GetTempFilePath("frid.txt"); + await File.WriteAllTextAsync(path, "content"); + + var file = await _fileHandler.GetFileFromPathAsync(path); + + file.FolderRelativeId.Should().NotBeNullOrEmpty(); + } + + [Test] + public async Task WinUIFile_GetSizeAsync_ReturnsAccurateSize() + { + var path = _fixture.GetTempFilePath("exact.txt"); + await File.WriteAllTextAsync(path, "hello", Encoding.ASCII); + var file = await _fileHandler.GetFileFromPathAsync(path); + + var size = await file.GetSizeAsync(); + + size.Should().Be(5UL, "the string \"hello\" written as ASCII is exactly 5 bytes"); + } + + #endregion + + #region Empty Folder Edge Cases + + [Test] + public async Task FolderHandler_GetFileAsync_EmptyFolder_ReturnsEmptyList() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "empty_for_files"); + var emptyFolder = await _folderHandler.GetFolderAsync(_rootFolder, "empty_for_files"); + + var files = await _folderHandler.GetFileAsync(emptyFolder); + + files.Should().BeEmpty(); + } + + [Test] + public async Task FolderHandler_GetFoldersAsync_EmptyFolder_ReturnsEmptyList() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "empty_for_folders"); + var emptyFolder = await _folderHandler.GetFolderAsync(_rootFolder, "empty_for_folders"); + + var folders = await _folderHandler.GetFoldersAsync(emptyFolder); + + folders.Should().BeEmpty(); + } + + [Test] + public async Task FolderHandler_GetItemsAsync_EmptyFolder_ReturnsEmptyList() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "empty_for_items"); + var emptyFolder = await _folderHandler.GetFolderAsync(_rootFolder, "empty_for_items"); + + var items = await _folderHandler.GetItemsAsync(emptyFolder); + + items.Should().BeEmpty(); + } + + #endregion + + #region GetItemAsync - Not Found + + [Test] + public async Task FolderHandler_GetItemAsync_ThrowsFileNotFoundException_WhenItemNotFound() + { + var act = async () => await _folderHandler.GetItemAsync(_rootFolder, "not_here.txt"); + + await act.Should().ThrowAsync(); + } + + #endregion + + #region Rename Removes Old Path + + [Test] + public async Task FileHandler_RenameAsync_OldPathNoLongerExists() + { + await _folderHandler.CreateFileAsync(_rootFolder, "ren_gone.txt"); + var file = await _folderHandler.GetFileAsync(_rootFolder, "ren_gone.txt"); + + await _fileHandler.RenameAsync(file, "ren_gone_new.txt"); + + File.Exists(Path.Combine(_fixture.RootPath, "ren_gone.txt")).Should().BeFalse(); + File.Exists(Path.Combine(_fixture.RootPath, "ren_gone_new.txt")).Should().BeTrue(); + } + + #endregion + + #region Open Async - Additional Options + + [Test] + public async Task FileHandler_OpenAsync_WithAllowReadersAndWriters_DoesNotThrow() + { + var path = _fixture.GetTempFilePath("arw.txt"); + await File.WriteAllTextAsync(path, "content"); + var file = await _fileHandler.GetFileFromPathAsync(path); + + var act = async () => await _fileHandler.OpenAsync(file, FileAccessMode.ReadWrite, StorageOpenOptions.AllowReadersAndWriters); + + await act.Should().NotThrowAsync(); + } + + #endregion + + #region StorageDeletionOption.Default + + [Test] + public async Task FolderHandler_DeleteAsync_WithDefaultOption_DeletesFolder() + { + await _folderHandler.CreateFolderAsync(_rootFolder, "del_default"); + var folder = await _folderHandler.GetFolderAsync(_rootFolder, "del_default"); + + await _folderHandler.DeleteAsync(folder, StorageDeletionOption.Default); + + Directory.Exists(Path.Combine(_fixture.RootPath, "del_default")).Should().BeFalse(); + } + + #endregion } diff --git a/Cyclotron.Tests/Unit/FileSystemAdapter/FileSystemAdapterTests.cs b/Cyclotron.Tests/Unit/FileSystemAdapter/FileSystemAdapterTests.cs index 6e6ff77..f3beda5 100644 --- a/Cyclotron.Tests/Unit/FileSystemAdapter/FileSystemAdapterTests.cs +++ b/Cyclotron.Tests/Unit/FileSystemAdapter/FileSystemAdapterTests.cs @@ -833,6 +833,254 @@ public async Task WinUIFolderHandler_RenameAsync_ThrowsArgumentException_WhenFol await act.Should().ThrowAsync(); } + [Test] + public async Task WinUIFileHandler_CopyAndReplaceAsync_ThrowsArgumentException_WhenDestNotWinUIFile() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var tempPath = Path.GetTempFileName(); + try + { + var realSource = await handler.GetFileFromPathAsync(tempPath); + + var act = async () => await handler.CopyAndReplaceAsync(realSource, Substitute.For()); + + await act.Should().ThrowAsync(); + } + finally + { + File.Delete(tempPath); + } + } + + [Test] + public async Task WinUIFileHandler_CopyAsync_ThrowsArgumentException_WhenDestFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var tempPath = Path.GetTempFileName(); + try + { + var realSource = await handler.GetFileFromPathAsync(tempPath); + + var act = async () => await handler.CopyAsync(realSource, Substitute.For(), "file.txt", NameCollisionOption.ReplaceExisting); + + await act.Should().ThrowAsync(); + } + finally + { + File.Delete(tempPath); + } + } + + [Test] + public async Task WinUIFileHandler_MoveAndReplaceAsync_ThrowsArgumentException_WhenDestNotWinUIFile() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var tempPath = Path.GetTempFileName(); + try + { + var realSource = await handler.GetFileFromPathAsync(tempPath); + + var act = async () => await handler.MoveAndReplaceAsync(realSource, Substitute.For()); + + await act.Should().ThrowAsync(); + } + finally + { + File.Delete(tempPath); + } + } + + [Test] + public async Task WinUIFileHandler_MoveAsync_ThrowsArgumentException_WhenDestFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var tempPath = Path.GetTempFileName(); + try + { + var realSource = await handler.GetFileFromPathAsync(tempPath); + + var act = async () => await handler.MoveAsync(realSource, Substitute.For()); + + await act.Should().ThrowAsync(); + } + finally + { + File.Delete(tempPath); + } + } + + [Test] + public async Task WinUIFileHandler_MoveAsync_WithName_ThrowsArgumentException_WhenFileNotWinUIFile() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFile = Substitute.For(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.MoveAsync(mockFile, mockFolder, "moved.txt"); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFileHandler_MoveAsync_WithName_ThrowsArgumentException_WhenDestFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var tempPath = Path.GetTempFileName(); + try + { + var realSource = await handler.GetFileFromPathAsync(tempPath); + + var act = async () => await handler.MoveAsync(realSource, Substitute.For(), "moved.txt"); + + await act.Should().ThrowAsync(); + } + finally + { + File.Delete(tempPath); + } + } + + [Test] + public async Task WinUIFileHandler_MoveAsync_WithNameAndOption_ThrowsArgumentException_WhenFileNotWinUIFile() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFile = Substitute.For(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.MoveAsync(mockFile, mockFolder, "moved.txt", NameCollisionOption.ReplaceExisting); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFileHandler_MoveAsync_WithNameAndOption_ThrowsArgumentException_WhenDestFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var tempPath = Path.GetTempFileName(); + try + { + var realSource = await handler.GetFileFromPathAsync(tempPath); + + var act = async () => await handler.MoveAsync(realSource, Substitute.For(), "moved.txt", NameCollisionOption.ReplaceExisting); + + await act.Should().ThrowAsync(); + } + finally + { + File.Delete(tempPath); + } + } + + [Test] + public async Task WinUIFolderHandler_CreateFileAsync_WithOption_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.CreateFileAsync(mockFolder, "f.txt", CreationCollisionOption.ReplaceExisting); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_CreateFolderAsync_WithOption_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.CreateFolderAsync(mockFolder, "sub", CreationCollisionOption.ReplaceExisting); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_DeleteAsync_WithOption_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.DeleteAsync(mockFolder, StorageDeletionOption.PermanentDelete); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_GetFileAsync_AllFiles_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.GetFileAsync(mockFolder); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_GetFoldersAsync_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.GetFoldersAsync(mockFolder); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_GetItemAsync_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.GetItemAsync(mockFolder, "item"); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_GetItemsAsync_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.GetItemsAsync(mockFolder); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_GetParentAsync_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.GetParentAsync(mockFolder); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_RenameAsync_WithOption_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.RenameAsync(mockFolder, "renamed", NameCollisionOption.GenerateUniqueName); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task WinUIFolderHandler_TryGetItemAsync_ThrowsArgumentException_WhenFolderNotWinUIFolder() + { + var handler = FileSystemProvider.Instance.GetRequiredService(); + var mockFolder = Substitute.For(); + + var act = async () => await handler.TryGetItemAsync(mockFolder, "item"); + + await act.Should().ThrowAsync(); + } + #endregion #region Constants