Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix several issues with CreateCopyOfAsync extension interface and method #72

Merged
merged 6 commits into from
Sep 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Install .NET 7 SDK
- name: Install .NET SDK
uses: actions/setup-dotnet@v1
with:
dotnet-version: '7.0.x'
dotnet-version: '8.0.x'

# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout Repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x

- name: Restore dependencies
run: dotnet restore
Expand Down
44 changes: 18 additions & 26 deletions src/Extensions/CopyAndMoveExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,28 @@ public static async Task<IChildFile> CreateCopyOfAsync(this IModifiableFolder de
{
static async Task<IChildFile> CreateCopyOfFallbackAsync(IModifiableFolder destinationFolder, IFile fileToCopy, bool overwrite, CancellationToken cancellationToken = default)
{
// Open the source file
using var sourceStream = await fileToCopy.OpenStreamAsync(FileAccess.Read, cancellationToken: cancellationToken);

// Create the destination file
var newFile = await destinationFolder.CreateFileAsync(fileToCopy.Name, overwrite, cancellationToken);
using var destinationStream = await newFile.OpenStreamAsync(FileAccess.ReadWrite, cancellationToken: cancellationToken);
cancellationToken.ThrowIfCancellationRequested();

// Align stream positions (if possible)
if (destinationStream.CanSeek && destinationStream.Position != 0)
destinationStream.Seek(0, SeekOrigin.Begin);
// If the destination file exists and overwrite is false, it shouldn't be overwritten or returned as-is. Throw an exception instead.
if (!overwrite)
{
try
{
var existing = await destinationFolder.GetFirstByNameAsync(fileToCopy.Name, cancellationToken);
if (existing is not null)
throw new FileAlreadyExistsException(fileToCopy.Name);
}
catch (FileNotFoundException) { }
}

if (sourceStream.CanSeek && sourceStream.Position != 0)
sourceStream.Seek(0, SeekOrigin.Begin);
// Create the destination file.
// 'overwrite: false' would have thrown above if the file exists, so either overwrite is already true or the file doesn't exist yet.
// Always overwrite here so the file is empty.
var newFile = await destinationFolder.CreateFileAsync(fileToCopy.Name, overwrite: true, cancellationToken);
using var destinationStream = await newFile.OpenStreamAsync(FileAccess.Write, cancellationToken: cancellationToken);

// Set stream length to zero to clear any existing data.
// Otherwise, writing less bytes than already exists would leave extra bytes at the end.
destinationStream.SetLength(0);
// Open the source file
using var sourceStream = await fileToCopy.OpenStreamAsync(FileAccess.Read, cancellationToken: cancellationToken);

// Copy the src into the dest file
await sourceStream.CopyToAsync(destinationStream, bufferSize: 81920, cancellationToken);
Expand All @@ -47,18 +51,6 @@ static async Task<IChildFile> CreateCopyOfFallbackAsync(IModifiableFolder destin
}

cancellationToken.ThrowIfCancellationRequested();

// If the destination file exists and overwrite is false, it shouldn't be overwritten or returned as-is. Throw an exception instead.
if (!overwrite)
{
try
{
var existing = await destinationFolder.GetFirstByNameAsync(fileToCopy.Name, cancellationToken);
if (existing is not null)
throw new FileAlreadyExistsException(fileToCopy.Name);
}
catch (FileNotFoundException) { }
}

// If the destination folder declares a non-fallback copy path, try that.
// Provide fallback in case this file is not a handled type.
Expand Down
1 change: 1 addition & 0 deletions src/Memory/MemoryFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public Task<Stream> OpenStreamAsync(FileAccess accessMode = FileAccess.Read, Can
if (accessMode == 0)
throw new ArgumentOutOfRangeException(nameof(accessMode), $"{nameof(FileAccess)}.{accessMode} is not valid here.");

_memoryStream.Position = 0;
return Task.FromResult<Stream>(new NonDisposableStreamWrapper(_memoryStream));
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/System/IO/SystemFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,18 +246,18 @@ public async Task<IChildFile> CreateCopyOfAsync(IFile fileToCopy, bool overwrite
// Handle using System.IO
var newPath = global::System.IO.Path.Combine(Path, systemFile.Name);

// If the source and destination are the same, there's no need to copy.
if (systemFile.Path == newPath)
return new SystemFile(newPath);

if (File.Exists(newPath))
{
if (!overwrite)
return new SystemFile(newPath, noValidation: true);
throw new FileAlreadyExistsException(fileToCopy.Name);

File.Delete(newPath);
}

// If the source and destination are the same, there's no need to copy.
if (systemFile.Path == newPath)
return systemFile;

File.Copy(systemFile.Path, newPath, overwrite);

return new SystemFile(newPath, noValidation: true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace OwlCore.Storage.Tests.Archive.ZipArchive;
/// A test suite for <see cref="ZipArchiveEntryFile"/>s created entirely in memory.
/// </summary>
[TestClass]
public class InMemIFileTests : CommonIFileTests
public class ZipArchiveEntryFile_FileInMemory_Tests : CommonIFileTests
{
// Required for base class to perform common tests.
public override Task<IFile> CreateFileAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
namespace OwlCore.Storage.Tests.Archive.ZipArchive;

[TestClass]
public class IFileTests : CommonIFileTests
public class ZipArchiveEntryFile_FileOnDisk_Tests : CommonIFileTests
{
// Required for base class to perform common tests.
public override async Task<IFile> CreateFileAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace OwlCore.Storage.Tests.Archive.ZipArchive;
/// A test suite for <see cref="ZipArchiveFolder"/>s created entirely in memory.
/// </summary>
[TestClass]
public class InMemIFolderTests : CommonIModifiableFolderTests
public class ZipArchiveFolder_FileInMemory_Tests : CommonIModifiableFolderTests
{
// Required for base class to perform common tests.
public override Task<IModifiableFolder> CreateModifiableFolderAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
namespace OwlCore.Storage.Tests.Archive.ZipArchive;

[TestClass]
public class IFolderTests : CommonIModifiableFolderTests
public class ZipArchiveFolder_FileOnDisk_Tests : CommonIModifiableFolderTests
{
// Required for base class to perform common tests.
public override async Task<IModifiableFolder> CreateModifiableFolderAsync()
public override Task<IModifiableFolder> CreateModifiableFolderAsync()
{
var sourceFile = new SystemFile(CreateEmptyArchiveOnDisk());
return new ZipArchiveFolder(sourceFile);
return Task.FromResult<IModifiableFolder>(new ZipArchiveFolder(sourceFile));
}

public override async Task<IModifiableFolder> CreateModifiableFolderWithItems(int fileCount, int folderCount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace OwlCore.Storage.Tests.Memory;

[TestClass]
public class IFolderTests : CommonIModifiableFolderTests
public class MemoryFolderTests : CommonIModifiableFolderTests
{
// Required for base class to perform common tests.
public override Task<IModifiableFolder> CreateModifiableFolderAsync()
Expand Down
2 changes: 1 addition & 1 deletion tests/OwlCore.Storage.Tests/OwlCore.Storage.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace OwlCore.Storage.Tests.SystemIO;

[TestClass]
public class IFileTests : CommonIFileTests
public class SystemFileTests : CommonIFileTests
{
// Required for base class to perform common tests.
public override async Task<IFile> CreateFileAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace OwlCore.Storage.Tests.SystemIO;

[TestClass]
public class IFolderTests : CommonIModifiableFolderTests
public class SystemFolderTests : CommonIModifiableFolderTests
{
public override Task<IModifiableFolder> CreateModifiableFolderAsync()
{
Expand Down
Loading