Skip to content

Commit

Permalink
feat: add new File methods from .NET 9 (#1193)
Browse files Browse the repository at this point in the history
- Task AppendAllBytesAsync(string, byte[], CancellationToken)
- Task AppendAllBytesAsync(string, ReadOnlyMemory<byte>, CancellationToken)
- Task AppendAllTextAsync(string, ReadOnlyMemory<char>, Encoding, CancellationToken)
- Task AppendAllTextAsync(string, ReadOnlyMemory<char>, CancellationToken)
- Task WriteAllBytesAsync(string, ReadOnlyMemory<byte>, CancellationToken)
- Task WriteAllTextAsync(string, ReadOnlyMemory<char>, Encoding, CancellationToken)
- Task WriteAllTextAsync(string, ReadOnlyMemory<char>, CancellationToken)
- void AppendAllBytes(string, byte[])
- void AppendAllBytes(string, ReadOnlySpan<byte>)
- void AppendAllText(string, ReadOnlySpan<char>)
- void AppendAllText(string, ReadOnlySpan<char>, Encoding)
- void WriteAllBytes(string, ReadOnlySpan<byte>)
- void WriteAllText(string, ReadOnlySpan<char>)
- void WriteAllText(string, ReadOnlySpan<char>, Encoding)
  • Loading branch information
vbreuss authored Jan 28, 2025
1 parent 5d1885d commit 15d0547
Show file tree
Hide file tree
Showing 11 changed files with 414 additions and 62 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<DefineConstants Condition="'$(TargetFramework)' == 'net9.0' OR '$(TargetFramework)' == 'net8.0' OR '$(TargetFramework)' == 'net7.0' OR '$(TargetFramework)' == 'net6.0' OR '$(TargetFramework)' == 'netstandard2.1'">$(DefineConstants);FEATURE_ASYNC_FILE;FEATURE_ENUMERATION_OPTIONS;FEATURE_ADVANCED_PATH_OPERATIONS;FEATURE_PATH_JOIN_WITH_SPAN;FEATURE_SPAN</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'net9.0' OR '$(TargetFramework)' == 'net8.0' OR '$(TargetFramework)' == 'net7.0' OR '$(TargetFramework)' == 'net6.0'">$(DefineConstants);FEATURE_FILE_MOVE_WITH_OVERWRITE;FEATURE_SUPPORTED_OS_ATTRIBUTE;FEATURE_FILE_SYSTEM_WATCHER_FILTERS;FEATURE_ENDS_IN_DIRECTORY_SEPARATOR;FEATURE_PATH_JOIN_WITH_PARAMS;FEATURE_PATH_JOIN_WITH_FOUR_PATHS;FEATURE_FILE_SYSTEM_INFO_LINK_TARGET;FEATURE_CREATE_SYMBOLIC_LINK;FEATURE_FILESTREAM_OPTIONS</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'net9.0' OR '$(TargetFramework)' == 'net8.0' OR '$(TargetFramework)' == 'net7.0'">$(DefineConstants);FEATURE_PATH_EXISTS;FEATURE_FILE_SYSTEM_WATCHER_WAIT_WITH_TIMESPAN;FEATURE_FILE_ATTRIBUTES_VIA_HANDLE;FEATURE_CREATE_TEMP_SUBDIRECTORY;FEATURE_READ_LINES_ASYNC;FEATURE_UNIX_FILE_MODE</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'net9.0'">$(DefineConstants);FEATURE_PATH_SPAN</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'net9.0'">$(DefineConstants);FEATURE_PATH_SPAN;FEATURE_FILE_SPAN</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_SERIALIZABLE</DefineConstants>
</PropertyGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,57 +10,87 @@ namespace System.IO.Abstractions.TestingHelpers
{
partial class MockFile
{
#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.AppendAllBytesAsync(string,byte[],CancellationToken)"/>
public override Task AppendAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
AppendAllBytes(path, bytes);
return Task.CompletedTask;
}

/// <inheritdoc cref="IFile.AppendAllBytesAsync(string,ReadOnlyMemory{byte},CancellationToken)"/>
public override Task AppendAllBytesAsync(string path, ReadOnlyMemory<byte> bytes, CancellationToken cancellationToken = default)
{
return AppendAllBytesAsync(path, bytes.ToArray(), cancellationToken);
}
#endif
/// <inheritdoc />
public override Task AppendAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken = default(CancellationToken)) =>
public override Task AppendAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken = default) =>
AppendAllLinesAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);

/// <inheritdoc />
public override Task AppendAllLinesAsync(string path, IEnumerable<string> contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
public override Task AppendAllLinesAsync(string path, IEnumerable<string> contents, Encoding encoding, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
AppendAllLines(path, contents, encoding);
return Task.CompletedTask;
}

/// <inheritdoc />
public override Task AppendAllTextAsync(string path, string contents, CancellationToken cancellationToken = default(CancellationToken)) =>
public override Task AppendAllTextAsync(string path, string contents, CancellationToken cancellationToken = default) =>
AppendAllTextAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);


/// <inheritdoc />
public override Task AppendAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
public override Task AppendAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
AppendAllText(path, contents, encoding);
return Task.CompletedTask;
}

#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.AppendAllTextAsync(string,ReadOnlyMemory{char},CancellationToken)"/>
public override Task AppendAllTextAsync(string path, ReadOnlyMemory<char> contents, CancellationToken cancellationToken = default)
{
return AppendAllTextAsync(path, contents.ToString(), cancellationToken);
}

/// <inheritdoc cref="IFile.AppendAllTextAsync(string,ReadOnlyMemory{char},Encoding,CancellationToken)"/>
public override Task AppendAllTextAsync(string path, ReadOnlyMemory<char> contents, Encoding encoding,
CancellationToken cancellationToken = default)
{
return AppendAllTextAsync(path, contents.ToString(), encoding, cancellationToken);
}
#endif

/// <inheritdoc />
public override Task<byte[]> ReadAllBytesAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
public override Task<byte[]> ReadAllBytesAsync(string path, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult(ReadAllBytes(path));
}

/// <inheritdoc />
public override Task<string[]> ReadAllLinesAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) =>
public override Task<string[]> ReadAllLinesAsync(string path, CancellationToken cancellationToken = default) =>
ReadAllLinesAsync(path, MockFileData.DefaultEncoding, cancellationToken);

/// <inheritdoc />

public override Task<string[]> ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
public override Task<string[]> ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult(ReadAllLines(path, encoding));
}

/// <inheritdoc />
public override Task<string> ReadAllTextAsync(string path, CancellationToken cancellationToken) =>
public override Task<string> ReadAllTextAsync(string path, CancellationToken cancellationToken = default) =>
ReadAllTextAsync(path, MockFileData.DefaultEncoding, cancellationToken);


/// <inheritdoc />
public override Task<string> ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken)
public override Task<string> ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult(ReadAllText(path, encoding));
Expand All @@ -82,36 +112,59 @@ public override async IAsyncEnumerable<string> ReadLinesAsync(string path, Encod
#endif

/// <inheritdoc />
public override Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken)
public override Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
WriteAllBytes(path, bytes);
return Task.CompletedTask;
}

#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.WriteAllBytesAsync(string,ReadOnlyMemory{byte},CancellationToken)"/>
public override Task WriteAllBytesAsync(string path, ReadOnlyMemory<byte> bytes, CancellationToken cancellationToken = default)
{
return WriteAllBytesAsync(path, bytes.ToArray(), cancellationToken);
}
#endif

/// <inheritdoc />
public override Task WriteAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken) =>
public override Task WriteAllLinesAsync(string path, IEnumerable<string> contents, CancellationToken cancellationToken = default) =>
WriteAllLinesAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);

/// <inheritdoc />
public override Task WriteAllLinesAsync(string path, IEnumerable<string> contents, Encoding encoding, CancellationToken cancellationToken)
public override Task WriteAllLinesAsync(string path, IEnumerable<string> contents, Encoding encoding, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
WriteAllLines(path, contents, encoding);
return Task.CompletedTask;
}

/// <inheritdoc />
public override Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken) =>
public override Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken = default) =>
WriteAllTextAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken);

/// <inheritdoc />
public override Task WriteAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken)
public override Task WriteAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
WriteAllText(path, contents, encoding);
return Task.CompletedTask;
}

#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.WriteAllTextAsync(string,ReadOnlyMemory{char},CancellationToken)"/>
public override Task WriteAllTextAsync(string path, ReadOnlyMemory<char> contents, CancellationToken cancellationToken = default)
{
return WriteAllTextAsync(path, contents.ToString(), cancellationToken);
}

/// <inheritdoc cref="IFile.WriteAllTextAsync(string,ReadOnlyMemory{char},Encoding,CancellationToken)"/>
public override Task WriteAllTextAsync(string path, ReadOnlyMemory<char> contents, Encoding encoding,
CancellationToken cancellationToken = default)
{
return WriteAllTextAsync(path, contents.ToString(), encoding, cancellationToken);
}
#endif
}
}

Expand Down
63 changes: 63 additions & 0 deletions src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,33 @@ public MockFile(IMockFileDataAccessor mockFileDataAccessor) : base(mockFileDataA
this.mockFileDataAccessor = mockFileDataAccessor ?? throw new ArgumentNullException(nameof(mockFileDataAccessor));
}

#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.AppendAllBytes(string,byte[])"/>
public override void AppendAllBytes(string path, byte[] bytes)
{
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");

if (!mockFileDataAccessor.FileExists(path))
{
VerifyDirectoryExists(path);
mockFileDataAccessor.AddFile(path, mockFileDataAccessor.AdjustTimes(new MockFileData(bytes), TimeAdjustments.All));
}
else
{
var file = mockFileDataAccessor.GetFile(path);
file.CheckFileAccess(path, FileAccess.Write);
mockFileDataAccessor.AdjustTimes(file, TimeAdjustments.LastAccessTime | TimeAdjustments.LastWriteTime);
file.Contents = file.Contents.Concat(bytes).ToArray();
}
}

/// <inheritdoc cref="IFile.AppendAllBytes(string,ReadOnlySpan{byte})"/>
public override void AppendAllBytes(string path, ReadOnlySpan<byte> bytes)
{
AppendAllBytes(path, bytes.ToArray());
}
#endif

/// <inheritdoc />
public override void AppendAllLines(string path, IEnumerable<string> contents)
{
Expand Down Expand Up @@ -70,6 +97,20 @@ public override void AppendAllText(string path, string contents, Encoding encodi
}
}

#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.AppendAllText(string,ReadOnlySpan{char})"/>
public override void AppendAllText(string path, ReadOnlySpan<char> contents)
{
AppendAllText(path, contents.ToString());
}

/// <inheritdoc cref="IFile.AppendAllText(string,ReadOnlySpan{char},Encoding)"/>
public override void AppendAllText(string path, ReadOnlySpan<char> contents, Encoding encoding)
{
AppendAllText(path, contents.ToString(), encoding);
}
#endif

/// <inheritdoc />
public override StreamWriter AppendText(string path)
{
Expand Down Expand Up @@ -1025,6 +1066,14 @@ public override void WriteAllBytes(string path, byte[] bytes)

mockFileDataAccessor.AddFile(path, mockFileDataAccessor.AdjustTimes(new MockFileData(bytes.ToArray()), TimeAdjustments.All));
}

#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.WriteAllBytes(string,ReadOnlySpan{byte})"/>
public override void WriteAllBytes(string path, ReadOnlySpan<byte> bytes)
{
WriteAllBytes(path, bytes.ToArray());
}
#endif

/// <summary>
/// Creates a new file, writes a collection of strings to the file, and then closes the file.
Expand Down Expand Up @@ -1296,6 +1345,20 @@ public override void WriteAllText(string path, string contents, Encoding encodin
mockFileDataAccessor.AddFile(path, mockFileDataAccessor.AdjustTimes(data, TimeAdjustments.All));
}

#if FEATURE_FILE_SPAN
/// <inheritdoc cref="IFile.WriteAllText(string,ReadOnlySpan{char})"/>
public override void WriteAllText(string path, ReadOnlySpan<char> contents)
{
WriteAllText(path, contents.ToString());
}

/// <inheritdoc cref="IFile.WriteAllText(string,ReadOnlySpan{char},Encoding)"/>
public override void WriteAllText(string path, ReadOnlySpan<char> contents, Encoding encoding)
{
WriteAllText(path, contents.ToString(), encoding);
}
#endif

internal static string ReadAllBytes(byte[] contents, Encoding encoding)
{
using (var ms = new MemoryStream(contents))
Expand Down
Loading

0 comments on commit 15d0547

Please sign in to comment.