Skip to content
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
71 changes: 71 additions & 0 deletions PolyShim.Tests/NetCore30/FileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.IO;
using FluentAssertions;
using Xunit;

namespace PolyShim.Tests.NetCore30;

public class FileTests
{
[Fact]
public void Move_Overwrite_TargetDoesNotExist_Test()
{
// Arrange
var sourceFileName = Path.GetTempFileName();
var destFileName = Path.GetTempFileName();

try
{
// Path.GetTempFileName() pre-creates the file, so delete it to simulate non-existence
File.Delete(destFileName);

// Act
File.Move(sourceFileName, destFileName, true);

// Assert
File.Exists(sourceFileName).Should().BeFalse();
File.Exists(destFileName).Should().BeTrue();
}
finally
{
try
{
File.Delete(sourceFileName);
File.Delete(destFileName);
}
catch
{
// Ignore
}
Comment on lines +35 to +38
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Copilot uses AI. Check for mistakes.
}
}

[Fact]
public void Move_Overwrite_TargetExists_Test()
{
// Arrange
var sourceFileName = Path.GetTempFileName();
var destFileName = Path.GetTempFileName();

try
{
// Act
File.Move(sourceFileName, destFileName, true);

// Assert
File.Exists(sourceFileName).Should().BeFalse();
File.Exists(destFileName).Should().BeTrue();
}
finally
{
try
{
File.Delete(sourceFileName);
File.Delete(destFileName);
}
catch
{
// Ignore
}
Comment on lines +65 to +68
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic catch clause.

Copilot uses AI. Check for mistakes.
}
}
}
28 changes: 28 additions & 0 deletions PolyShim/NetCore30/File.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// The following comment is required to instruct analyzers to skip this file
// <auto-generated/>

#if (NETCOREAPP && !NETCOREAPP3_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD)
#nullable enable
// ReSharper disable RedundantUsingDirective
// ReSharper disable CheckNamespace
// ReSharper disable InconsistentNaming
// ReSharper disable PartialTypeWithSinglePart

using System.IO;

internal static partial class PolyfillExtensions
{
// No file I/O on .NET Standard prior to 1.3
#if !NETSTANDARD || NETSTANDARD1_3_OR_GREATER
extension(File)
{
// https://learn.microsoft.com/dotnet/api/system.io.file.move#system-io-file-move(system-string-system-string-system-boolean)
public static void Move(string sourceFileName, string destFileName, bool overwrite)
{
File.Copy(sourceFileName, destFileName, overwrite);
File.Delete(sourceFileName);
}
Comment on lines +23 to +24
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The polyfill implementation is not atomic and could leave the file in both locations if File.Delete fails after File.Copy succeeds. Consider wrapping the delete in a try-catch and handling potential failures, or document this limitation. The standard File.Move is atomic on most filesystems.

Suggested change
File.Delete(sourceFileName);
}
// WARNING: This polyfill is not atomic. If File.Delete fails after File.Copy succeeds,
// the file may exist in both locations. The standard File.Move is atomic on most filesystems.
try
{
File.Delete(sourceFileName);
}
catch (IOException ex)
{
// Optionally, handle or log the error here.
// For now, rethrow to preserve original behavior.
throw;
}

Copilot uses AI. Check for mistakes.
}
#endif
}
#endif
Loading