diff --git a/Directory.Build.props b/Directory.Build.props index a02382776..e10731833 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ $(DefineConstants);FEATURE_ASYNC_FILE;FEATURE_ENUMERATION_OPTIONS;FEATURE_ADVANCED_PATH_OPERATIONS;FEATURE_PATH_JOIN_WITH_SPAN;FEATURE_SPAN $(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);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);FEATURE_PATH_SPAN + $(DefineConstants);FEATURE_PATH_SPAN;FEATURE_FILE_SPAN $(DefineConstants);FEATURE_SERIALIZABLE diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.Async.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.Async.cs index fd4a764f9..b4765c93a 100644 --- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.Async.cs +++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.Async.cs @@ -10,12 +10,27 @@ namespace System.IO.Abstractions.TestingHelpers { partial class MockFile { +#if FEATURE_FILE_SPAN + /// + public override Task AppendAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + AppendAllBytes(path, bytes); + return Task.CompletedTask; + } + + /// + public override Task AppendAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default) + { + return AppendAllBytesAsync(path, bytes.ToArray(), cancellationToken); + } +#endif /// - public override Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default(CancellationToken)) => + public override Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default) => AppendAllLinesAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken); /// - public override Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken)) + public override Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); AppendAllLines(path, contents, encoding); @@ -23,44 +38,59 @@ partial class MockFile } /// - 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); /// - 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 + /// + public override Task AppendAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default) + { + return AppendAllTextAsync(path, contents.ToString(), cancellationToken); + } + + /// + public override Task AppendAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, + CancellationToken cancellationToken = default) + { + return AppendAllTextAsync(path, contents.ToString(), encoding, cancellationToken); + } +#endif /// - public override Task ReadAllBytesAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) + public override Task ReadAllBytesAsync(string path, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); return Task.FromResult(ReadAllBytes(path)); } /// - public override Task ReadAllLinesAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) => + public override Task ReadAllLinesAsync(string path, CancellationToken cancellationToken = default) => ReadAllLinesAsync(path, MockFileData.DefaultEncoding, cancellationToken); /// - public override Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken)) + public override Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); return Task.FromResult(ReadAllLines(path, encoding)); } /// - public override Task ReadAllTextAsync(string path, CancellationToken cancellationToken) => + public override Task ReadAllTextAsync(string path, CancellationToken cancellationToken = default) => ReadAllTextAsync(path, MockFileData.DefaultEncoding, cancellationToken); /// - public override Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken) + public override Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); return Task.FromResult(ReadAllText(path, encoding)); @@ -82,19 +112,27 @@ public override async IAsyncEnumerable ReadLinesAsync(string path, Encod #endif /// - 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 + /// + public override Task WriteAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default) + { + return WriteAllBytesAsync(path, bytes.ToArray(), cancellationToken); + } +#endif /// - public override Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken) => + public override Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default) => WriteAllLinesAsync(path, contents, MockFileData.DefaultEncoding, cancellationToken); /// - public override Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken) + public override Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); WriteAllLines(path, contents, encoding); @@ -102,16 +140,31 @@ public override Task WriteAllLinesAsync(string path, IEnumerable content } /// - 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); /// - 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 + /// + public override Task WriteAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default) + { + return WriteAllTextAsync(path, contents.ToString(), cancellationToken); + } + + /// + public override Task WriteAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, + CancellationToken cancellationToken = default) + { + return WriteAllTextAsync(path, contents.ToString(), encoding, cancellationToken); + } +#endif } } diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs index fd1a08af2..3f025bd34 100644 --- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs +++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs @@ -22,6 +22,33 @@ public MockFile(IMockFileDataAccessor mockFileDataAccessor) : base(mockFileDataA this.mockFileDataAccessor = mockFileDataAccessor ?? throw new ArgumentNullException(nameof(mockFileDataAccessor)); } +#if FEATURE_FILE_SPAN + /// + 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(); + } + } + + /// + public override void AppendAllBytes(string path, ReadOnlySpan bytes) + { + AppendAllBytes(path, bytes.ToArray()); + } +#endif + /// public override void AppendAllLines(string path, IEnumerable contents) { @@ -70,6 +97,20 @@ public override void AppendAllText(string path, string contents, Encoding encodi } } +#if FEATURE_FILE_SPAN + /// + public override void AppendAllText(string path, ReadOnlySpan contents) + { + AppendAllText(path, contents.ToString()); + } + + /// + public override void AppendAllText(string path, ReadOnlySpan contents, Encoding encoding) + { + AppendAllText(path, contents.ToString(), encoding); + } +#endif + /// public override StreamWriter AppendText(string path) { @@ -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 + /// + public override void WriteAllBytes(string path, ReadOnlySpan bytes) + { + WriteAllBytes(path, bytes.ToArray()); + } +#endif /// /// Creates a new file, writes a collection of strings to the file, and then closes the file. @@ -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 + /// + public override void WriteAllText(string path, ReadOnlySpan contents) + { + WriteAllText(path, contents.ToString()); + } + + /// + public override void WriteAllText(string path, ReadOnlySpan contents, Encoding encoding) + { + WriteAllText(path, contents.ToString(), encoding); + } +#endif + internal static string ReadAllBytes(byte[] contents, Encoding encoding) { using (var ms = new MemoryStream(contents)) diff --git a/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.Async.cs b/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.Async.cs index d91efcf92..edf2f436d 100644 --- a/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.Async.cs +++ b/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.Async.cs @@ -9,31 +9,52 @@ namespace System.IO.Abstractions { partial class FileBase { +#if FEATURE_FILE_SPAN + /// + public abstract Task AppendAllBytesAsync(string path, byte[] bytes, + CancellationToken cancellationToken = default); + + /// + public abstract Task AppendAllBytesAsync(string path, ReadOnlyMemory bytes, + CancellationToken cancellationToken = default); +#endif + /// - public abstract Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken); + public abstract Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default); /// - public abstract Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken); + public abstract Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default); /// - public abstract Task AppendAllTextAsync(String path, String contents, CancellationToken cancellationToken); + public abstract Task AppendAllTextAsync(String path, String contents, CancellationToken cancellationToken = default); /// - public abstract Task AppendAllTextAsync(String path, String contents, Encoding encoding, CancellationToken cancellationToken); + public abstract Task AppendAllTextAsync(String path, String contents, Encoding encoding, CancellationToken cancellationToken = default); + +#if FEATURE_FILE_SPAN + /// + public abstract Task AppendAllTextAsync(string path, ReadOnlyMemory contents, + CancellationToken cancellationToken = default); + + /// + public abstract Task AppendAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, + CancellationToken cancellationToken = default); +#endif + /// - public abstract Task ReadAllBytesAsync(string path, CancellationToken cancellationToken); + public abstract Task ReadAllBytesAsync(string path, CancellationToken cancellationToken = default); /// - public abstract Task ReadAllLinesAsync(string path, CancellationToken cancellationToken); + public abstract Task ReadAllLinesAsync(string path, CancellationToken cancellationToken = default); /// - public abstract Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken); + public abstract Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default); /// - public abstract Task ReadAllTextAsync(string path, CancellationToken cancellationToken); + public abstract Task ReadAllTextAsync(string path, CancellationToken cancellationToken = default); /// - public abstract Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken); + public abstract Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default); #if FEATURE_READ_LINES_ASYNC /// @@ -45,20 +66,36 @@ public abstract IAsyncEnumerable ReadLinesAsync(string path, Encoding en CancellationToken cancellationToken = default); #endif - /// - public abstract Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken); + /// + public abstract Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default); + +#if FEATURE_FILE_SPAN + /// + public abstract Task WriteAllBytesAsync(string path, ReadOnlyMemory bytes, + CancellationToken cancellationToken = default); +#endif /// - public abstract Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken); + public abstract Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default); /// - public abstract Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken); + public abstract Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default); /// - public abstract Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken); + public abstract Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken = default); /// - public abstract Task WriteAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken); + public abstract Task WriteAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default); + +#if FEATURE_FILE_SPAN + /// + public abstract Task WriteAllTextAsync(string path, ReadOnlyMemory contents, + CancellationToken cancellationToken = default); + + /// + public abstract Task WriteAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, + CancellationToken cancellationToken = default); +#endif } } diff --git a/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.cs b/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.cs index a5d25c51d..d5c7234a6 100644 --- a/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.cs +++ b/src/TestableIO.System.IO.Abstractions.Wrappers/FileBase.cs @@ -24,6 +24,14 @@ internal FileBase() { } /// public IFileSystem FileSystem { get; } +#if FEATURE_FILE_SPAN + /// + public abstract void AppendAllBytes(string path, byte[] bytes); + + /// + public abstract void AppendAllBytes(string path, ReadOnlySpan bytes); +#endif + /// public abstract void AppendAllLines(string path, IEnumerable contents); @@ -36,6 +44,14 @@ internal FileBase() { } /// public abstract void AppendAllText(string path, string contents, Encoding encoding); +#if FEATURE_FILE_SPAN + /// + public abstract void AppendAllText(string path, ReadOnlySpan contents); + + /// + public abstract void AppendAllText(string path, ReadOnlySpan contents, Encoding encoding); +#endif + /// public abstract StreamWriter AppendText(string path); @@ -271,6 +287,11 @@ internal FileBase() { } /// public abstract void WriteAllBytes(string path, byte[] bytes); +#if FEATURE_FILE_SPAN + /// + public abstract void WriteAllBytes(string path, ReadOnlySpan bytes); +#endif + /// public abstract void WriteAllLines(string path, IEnumerable contents); @@ -288,5 +309,13 @@ internal FileBase() { } /// public abstract void WriteAllText(string path, string contents, Encoding encoding); + +#if FEATURE_FILE_SPAN + /// + public abstract void WriteAllText(string path, ReadOnlySpan contents); + + /// + public abstract void WriteAllText(string path, ReadOnlySpan contents, Encoding encoding); +#endif } } diff --git a/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.Async.cs b/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.Async.cs index ff4f953e2..968312d32 100644 --- a/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.Async.cs +++ b/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.Async.cs @@ -9,56 +9,84 @@ namespace System.IO.Abstractions { partial class FileWrapper { +#if FEATURE_FILE_SPAN + /// + public override Task AppendAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default) + { + return File.AppendAllBytesAsync(path, bytes, cancellationToken); + } + + /// + public override Task AppendAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default) + { + return File.AppendAllBytesAsync(path, bytes, cancellationToken); + } +#endif /// - public override Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken) + public override Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default) { return File.AppendAllLinesAsync(path, contents, cancellationToken); } /// - public override Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken) + public override Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default) { return File.AppendAllLinesAsync(path, contents, encoding, cancellationToken); } /// - public override Task AppendAllTextAsync(string path, string contents, CancellationToken cancellationToken) + public override Task AppendAllTextAsync(string path, string contents, CancellationToken cancellationToken = default) { return File.AppendAllTextAsync(path, contents, cancellationToken); } /// - public override Task AppendAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken) + public override Task AppendAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default) + { + return File.AppendAllTextAsync(path, contents, encoding, cancellationToken); + } + +#if FEATURE_FILE_SPAN + /// + public override Task AppendAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default) + { + return File.AppendAllTextAsync(path, contents, cancellationToken); + } + + /// + public override Task AppendAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, + CancellationToken cancellationToken = default) { return File.AppendAllTextAsync(path, contents, encoding, cancellationToken); } +#endif /// - public override Task ReadAllBytesAsync(string path, CancellationToken cancellationToken) + public override Task ReadAllBytesAsync(string path, CancellationToken cancellationToken = default) { return File.ReadAllBytesAsync(path, cancellationToken); } /// - public override Task ReadAllLinesAsync(string path, CancellationToken cancellationToken) + public override Task ReadAllLinesAsync(string path, CancellationToken cancellationToken = default) { return File.ReadAllLinesAsync(path, cancellationToken); } /// - public override Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken) + public override Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default) { return File.ReadAllLinesAsync(path, encoding, cancellationToken); } /// - public override Task ReadAllTextAsync(string path, CancellationToken cancellationToken) + public override Task ReadAllTextAsync(string path, CancellationToken cancellationToken = default) { return File.ReadAllTextAsync(path, cancellationToken); } /// - public override Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken) + public override Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default) { return File.ReadAllTextAsync(path, encoding, cancellationToken); } @@ -76,34 +104,57 @@ public override IAsyncEnumerable ReadLinesAsync(string path, Encoding en #endif /// - public override Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken) + public override Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default) + { + return File.WriteAllBytesAsync(path, bytes, cancellationToken); + } + +#if FEATURE_FILE_SPAN + /// + public override Task WriteAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default) { return File.WriteAllBytesAsync(path, bytes, cancellationToken); } +#endif /// - public override Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken) + public override Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default) { return File.WriteAllLinesAsync(path, contents, cancellationToken); } /// - public override Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken) + public override Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default) { return File.WriteAllLinesAsync(path, contents, encoding, cancellationToken); } /// - public override Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken) + public override Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken = default) { return File.WriteAllTextAsync(path, contents, cancellationToken); } /// - 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) + { + return File.WriteAllTextAsync(path, contents, encoding, cancellationToken); + } + +#if FEATURE_FILE_SPAN + /// + public override Task WriteAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default) + { + return File.WriteAllTextAsync(path, contents, cancellationToken); + } + + /// + public override Task WriteAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, + CancellationToken cancellationToken = default) { return File.WriteAllTextAsync(path, contents, encoding, cancellationToken); } +#endif } } #endif diff --git a/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.cs b/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.cs index 8f1f5512d..12cc91fe8 100644 --- a/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.cs +++ b/src/TestableIO.System.IO.Abstractions.Wrappers/FileWrapper.cs @@ -16,6 +16,20 @@ public FileWrapper(IFileSystem fileSystem) : base(fileSystem) { } +#if FEATURE_FILE_SPAN + /// + public override void AppendAllBytes(string path, byte[] bytes) + { + File.AppendAllBytes(path, bytes); + } + + /// + public override void AppendAllBytes(string path, ReadOnlySpan bytes) + { + File.AppendAllBytes(path, bytes); + } +#endif + /// public override void AppendAllLines(string path, IEnumerable contents) { @@ -41,6 +55,20 @@ public override void AppendAllText(string path, string contents, Encoding encodi File.AppendAllText(path, contents, encoding); } +#if FEATURE_FILE_SPAN + /// + public override void AppendAllText(string path, ReadOnlySpan contents) + { + File.AppendAllText(path, contents); + } + + /// + public override void AppendAllText(string path, ReadOnlySpan contents, Encoding encoding) + { + File.AppendAllText(path, contents, encoding); + } +#endif + /// public override StreamWriter AppendText(string path) { @@ -504,6 +532,14 @@ public override void WriteAllBytes(string path, byte[] bytes) { File.WriteAllBytes(path, bytes); } + +#if FEATURE_FILE_SPAN + /// + public override void WriteAllBytes(string path, ReadOnlySpan bytes) + { + File.WriteAllBytes(path, bytes); + } +#endif /// /// Creates a new file, writes a collection of strings to the file, and then closes the file. @@ -743,5 +779,19 @@ public override void WriteAllText(string path, string contents, Encoding encodin { File.WriteAllText(path, contents, encoding); } + +#if FEATURE_FILE_SPAN + /// + public override void WriteAllText(string path, ReadOnlySpan contents) + { + File.WriteAllText(path, contents); + } + + /// + public override void WriteAllText(string path, ReadOnlySpan contents, Encoding encoding) + { + File.WriteAllText(path, contents, encoding); + } +#endif } } diff --git a/src/TestableIO.System.IO.Abstractions/IFile.Async.cs b/src/TestableIO.System.IO.Abstractions/IFile.Async.cs index ec1db7f8c..0571d71dc 100644 --- a/src/TestableIO.System.IO.Abstractions/IFile.Async.cs +++ b/src/TestableIO.System.IO.Abstractions/IFile.Async.cs @@ -9,6 +9,18 @@ namespace System.IO.Abstractions { partial interface IFile { +#if FEATURE_FILE_SPAN + /// + Task AppendAllBytesAsync(string path, + byte[] bytes, + CancellationToken cancellationToken = default); + + /// + Task AppendAllBytesAsync(string path, + ReadOnlyMemory bytes, + CancellationToken cancellationToken = default); +#endif + /// Task AppendAllLinesAsync(string path, IEnumerable contents, @@ -31,6 +43,19 @@ Task AppendAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default); +#if FEATURE_FILE_SPAN + /// + Task AppendAllTextAsync(string path, + ReadOnlyMemory contents, + CancellationToken cancellationToken = default); + + /// + Task AppendAllTextAsync(string path, + ReadOnlyMemory contents, + Encoding encoding, + CancellationToken cancellationToken = default); +#endif + /// Task ReadAllBytesAsync(string path, CancellationToken cancellationToken = default); @@ -71,6 +96,13 @@ Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default); +#if FEATURE_FILE_SPAN + /// + Task WriteAllBytesAsync(string path, + ReadOnlyMemory bytes, + CancellationToken cancellationToken = default); +#endif + /// Task WriteAllLinesAsync(string path, IEnumerable contents, @@ -92,6 +124,19 @@ Task WriteAllTextAsync(string path, string? contents, Encoding encoding, CancellationToken cancellationToken = default); + +#if FEATURE_FILE_SPAN + /// + Task WriteAllTextAsync(string path, + ReadOnlyMemory contents, + CancellationToken cancellationToken = default); + + /// + Task WriteAllTextAsync(string path, + ReadOnlyMemory contents, + Encoding encoding, + CancellationToken cancellationToken = default); +#endif } } diff --git a/src/TestableIO.System.IO.Abstractions/IFile.cs b/src/TestableIO.System.IO.Abstractions/IFile.cs index 970635a2d..e7b029ac1 100644 --- a/src/TestableIO.System.IO.Abstractions/IFile.cs +++ b/src/TestableIO.System.IO.Abstractions/IFile.cs @@ -15,6 +15,16 @@ public partial interface IFile : IFileSystemEntity public interface IFile : IFileSystemEntity #endif { +#if FEATURE_FILE_SPAN + /// + void AppendAllBytes(string path, + byte[] bytes); + + /// + void AppendAllBytes(string path, + ReadOnlySpan bytes); +#endif + /// void AppendAllLines(string path, IEnumerable contents); @@ -27,6 +37,17 @@ public interface IFile : IFileSystemEntity /// void AppendAllText(string path, string? contents, Encoding encoding); +#if FEATURE_FILE_SPAN + /// + void AppendAllText(string path, + ReadOnlySpan contents); + + /// + void AppendAllText(string path, + ReadOnlySpan contents, + Encoding encoding); +#endif + /// StreamWriter AppendText(string path); @@ -274,6 +295,12 @@ void Replace(string sourceFileName, /// void WriteAllBytes(string path, byte[] bytes); +#if FEATURE_FILE_SPAN + /// + void WriteAllBytes(string path, + ReadOnlySpan bytes); +#endif + /// void WriteAllLines(string path, string[] contents); @@ -291,5 +318,16 @@ void Replace(string sourceFileName, /// void WriteAllText(string path, string? contents, Encoding encoding); + +#if FEATURE_FILE_SPAN + /// + void WriteAllText(string path, + ReadOnlySpan contents); + + /// + void WriteAllText(string path, + ReadOnlySpan contents, + Encoding encoding); +#endif } } \ No newline at end of file diff --git a/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileWriteAllTextTests.cs b/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileWriteAllTextTests.cs index 95fdf2f03..98b1a5449 100644 --- a/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileWriteAllTextTests.cs +++ b/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileWriteAllTextTests.cs @@ -315,7 +315,7 @@ public async Task MockFile_WriteAllTextAsync_ShouldNotThrowAnArgumentNullExcepti fileSystem.AddDirectory(directoryPath); // Act - await fileSystem.File.WriteAllTextAsync(filePath, null); + await fileSystem.File.WriteAllTextAsync(filePath, ""); // Assert // no exception should be thrown, also the documentation says so @@ -334,7 +334,7 @@ public void MockFile_WriteAllTextAsync_ShouldThrowAnUnauthorizedAccessExceptionI fileSystem.AddFile(filePath, mockFileData); // Act - AsyncTestDelegate action = () => fileSystem.File.WriteAllTextAsync(filePath, null); + AsyncTestDelegate action = () => fileSystem.File.WriteAllTextAsync(filePath, ""); // Assert Assert.ThrowsAsync(action); @@ -349,7 +349,7 @@ public void MockFile_WriteAllTextAsync_ShouldThrowAnUnauthorizedAccessExceptionI fileSystem.AddDirectory(directoryPath); // Act - AsyncTestDelegate action = () => fileSystem.File.WriteAllTextAsync(directoryPath, null); + AsyncTestDelegate action = () => fileSystem.File.WriteAllTextAsync(directoryPath, ""); // Assert Assert.ThrowsAsync(action); diff --git a/tests/TestableIO.System.IO.Abstractions.Wrappers.Tests/__snapshots__/ApiParityTests.File_.NET 9.0.snap b/tests/TestableIO.System.IO.Abstractions.Wrappers.Tests/__snapshots__/ApiParityTests.File_.NET 9.0.snap index c26706726..ce42363ab 100644 --- a/tests/TestableIO.System.IO.Abstractions.Wrappers.Tests/__snapshots__/ApiParityTests.File_.NET 9.0.snap +++ b/tests/TestableIO.System.IO.Abstractions.Wrappers.Tests/__snapshots__/ApiParityTests.File_.NET 9.0.snap @@ -1,20 +1,6 @@ { "ExtraMembers": [], "MissingMembers": [ - "Microsoft.Win32.SafeHandles.SafeFileHandle OpenHandle(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, System.IO.FileOptions, Int64)", - "System.Threading.Tasks.Task AppendAllBytesAsync(System.String, Byte[], System.Threading.CancellationToken)", - "System.Threading.Tasks.Task AppendAllBytesAsync(System.String, System.ReadOnlyMemory`1[System.Byte], System.Threading.CancellationToken)", - "System.Threading.Tasks.Task AppendAllTextAsync(System.String, System.ReadOnlyMemory`1[System.Char], System.Text.Encoding, System.Threading.CancellationToken)", - "System.Threading.Tasks.Task AppendAllTextAsync(System.String, System.ReadOnlyMemory`1[System.Char], System.Threading.CancellationToken)", - "System.Threading.Tasks.Task WriteAllBytesAsync(System.String, System.ReadOnlyMemory`1[System.Byte], System.Threading.CancellationToken)", - "System.Threading.Tasks.Task WriteAllTextAsync(System.String, System.ReadOnlyMemory`1[System.Char], System.Text.Encoding, System.Threading.CancellationToken)", - "System.Threading.Tasks.Task WriteAllTextAsync(System.String, System.ReadOnlyMemory`1[System.Char], System.Threading.CancellationToken)", - "Void AppendAllBytes(System.String, Byte[])", - "Void AppendAllBytes(System.String, System.ReadOnlySpan`1[System.Byte])", - "Void AppendAllText(System.String, System.ReadOnlySpan`1[System.Char])", - "Void AppendAllText(System.String, System.ReadOnlySpan`1[System.Char], System.Text.Encoding)", - "Void WriteAllBytes(System.String, System.ReadOnlySpan`1[System.Byte])", - "Void WriteAllText(System.String, System.ReadOnlySpan`1[System.Char])", - "Void WriteAllText(System.String, System.ReadOnlySpan`1[System.Char], System.Text.Encoding)" + "Microsoft.Win32.SafeHandles.SafeFileHandle OpenHandle(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, System.IO.FileOptions, Int64)" ] }