diff --git a/System.IO.Abstractions/FileStreamFactory.cs b/System.IO.Abstractions/FileStreamFactory.cs new file mode 100644 index 000000000..060c90eac --- /dev/null +++ b/System.IO.Abstractions/FileStreamFactory.cs @@ -0,0 +1,62 @@ +using System.Security.AccessControl; +using Microsoft.Win32.SafeHandles; + +namespace System.IO.Abstractions +{ + [Serializable] + internal sealed class FileStreamFactory : IFileStreamFactory + { + public Stream Create(string path, FileMode mode) + => new FileStream(path, mode); + + public Stream Create(string path, FileMode mode, FileAccess access) + => new FileStream(path, mode, access); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share) + => new FileStream(path, mode, access, share); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize) + => new FileStream(path, mode, access, share, bufferSize); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options) + => new FileStream(path, mode, access, share, bufferSize, options); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync) + => new FileStream(path, mode, access, share, bufferSize, useAsync); + + public Stream Create(SafeFileHandle handle, FileAccess access) + => new FileStream(handle, access); + + public Stream Create(SafeFileHandle handle, FileAccess access, int bufferSize) + => new FileStream(handle, access, bufferSize); + + public Stream Create(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) + => new FileStream(handle, access, bufferSize, isAsync); + +#if NET40 + public Stream Create(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity fileSecurity) + => new FileStream(path, mode, rights, share, bufferSize, options, fileSecurity); + + public Stream Create(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options) + => new FileStream(path, mode, rights, share, bufferSize, options); +#endif + +#if NET40 || NETSTANDARD_20 + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access) instead. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access) + => new FileStream(handle, access); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access, bool ownsHandle) + => new FileStream(handle, access, ownsHandle); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access, int bufferSize) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize) + => new FileStream(handle, access, ownsHandle, bufferSize); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync) + => new FileStream(handle, access, ownsHandle, bufferSize, isAsync); +#endif + } +} \ No newline at end of file diff --git a/System.IO.Abstractions/FileSystem.cs b/System.IO.Abstractions/FileSystem.cs index 08db46245..596ff655e 100644 --- a/System.IO.Abstractions/FileSystem.cs +++ b/System.IO.Abstractions/FileSystem.cs @@ -21,6 +21,12 @@ public IFileInfoFactory FileInfo get { return fileInfoFactory ?? (fileInfoFactory = new FileInfoFactory()); } } + FileStreamFactory fileStreamFactory; + public IFileStreamFactory FileStream + { + get { return fileStreamFactory ?? (fileStreamFactory = new FileStreamFactory()); } + } + PathBase path; public PathBase Path { diff --git a/System.IO.Abstractions/IFileStreamFactory.cs b/System.IO.Abstractions/IFileStreamFactory.cs new file mode 100644 index 000000000..3114c83d8 --- /dev/null +++ b/System.IO.Abstractions/IFileStreamFactory.cs @@ -0,0 +1,46 @@ +using System.Security.AccessControl; +using Microsoft.Win32.SafeHandles; + +namespace System.IO.Abstractions +{ + public interface IFileStreamFactory + { + Stream Create(string path, FileMode mode); + + Stream Create(string path, FileMode mode, FileAccess access); + + Stream Create(string path, FileMode mode, FileAccess access, FileShare share); + + Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize); + + Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options); + + Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync); + + Stream Create(SafeFileHandle handle, FileAccess access); + + Stream Create(SafeFileHandle handle, FileAccess access, int bufferSize); + + Stream Create(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync); + +#if NET40 + Stream Create(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity fileSecurity); + + Stream Create(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options); +#endif + +#if NET40 || NETSTANDARD_20 + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access) instead. http://go.microsoft.com/fwlink/?linkid=14202")] + Stream Create(IntPtr handle, FileAccess access); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + Stream Create(IntPtr handle, FileAccess access, bool ownsHandle); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access, int bufferSize) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + Stream Create(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + Stream Create(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync); +#endif + } +} \ No newline at end of file diff --git a/System.IO.Abstractions/IFileSystem.cs b/System.IO.Abstractions/IFileSystem.cs index c88c962e3..32472125e 100644 --- a/System.IO.Abstractions/IFileSystem.cs +++ b/System.IO.Abstractions/IFileSystem.cs @@ -5,6 +5,7 @@ public interface IFileSystem FileBase File { get; } DirectoryBase Directory { get; } IFileInfoFactory FileInfo { get; } + IFileStreamFactory FileStream { get; } PathBase Path { get; } IDirectoryInfoFactory DirectoryInfo { get; } IDriveInfoFactory DriveInfo { get; } diff --git a/System.IO.Abstractions/System.IO.Abstractions.csproj b/System.IO.Abstractions/System.IO.Abstractions.csproj index 726d749e1..0fcfa6d64 100644 --- a/System.IO.Abstractions/System.IO.Abstractions.csproj +++ b/System.IO.Abstractions/System.IO.Abstractions.csproj @@ -1,4 +1,4 @@ - + net40;netstandard1.4;netstandard2.0; diff --git a/System.IO.Abstractions/System.IO.Abstractions.nuspec b/System.IO.Abstractions/System.IO.Abstractions.nuspec deleted file mode 100644 index 306cece32..000000000 --- a/System.IO.Abstractions/System.IO.Abstractions.nuspec +++ /dev/null @@ -1,14 +0,0 @@ - - - - System.IO.Abstractions - $version$ - Tatham Oddie & friends - Tatham Oddie & friends - https://github.com/System-IO-Abstractions/System.IO.Abstractions/blob/master/License.txt - https://github.com/System-IO-Abstractions/System.IO.Abstractions - false - Just like System.Web.Abstractions, but for System.IO. Yay for testable IO access! Be sure to check out the System.IO.Abstractions.TestingHelpers package too. - testing - - \ No newline at end of file diff --git a/TestHelpers.Tests/MockFileStreamFactoryTests.cs b/TestHelpers.Tests/MockFileStreamFactoryTests.cs new file mode 100644 index 000000000..e11b6277d --- /dev/null +++ b/TestHelpers.Tests/MockFileStreamFactoryTests.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using NUnit.Framework; + +namespace System.IO.Abstractions.TestingHelpers.Tests +{ + [TestFixture] + public class MockFileStreamFactoryTests + { + [Test] + [TestCase(FileMode.Create)] + [TestCase(FileMode.Append)] + public void MockFileStreamFactory_CreateForExistingFile_ShouldReturnStream(FileMode fileMode) + { + // Arrange + var fileSystem = new MockFileSystem(new Dictionary + { + { @"c:\existing.txt", MockFileData.NullObject } + }); + + var fileStreamFactory = new MockFileStreamFactory(fileSystem); + + // Act + var result = fileStreamFactory.Create(@"c:\existing.txt", fileMode); + + // Assert + Assert.IsNotNull(result); + } + + [Test] + [TestCase(FileMode.Create)] + [TestCase(FileMode.Append)] + public void MockFileStreamFactory_CreateForNonExistingFile_ShouldReturnStream(FileMode fileMode) + { + // Arrange + var fileSystem = new MockFileSystem(); + var fileStreamFactory = new MockFileStreamFactory(fileSystem); + + // Act + var result = fileStreamFactory.Create(@"c:\not_existing.txt", fileMode); + + // Assert + Assert.IsNotNull(result); + } + } +} \ No newline at end of file diff --git a/TestingHelpers/MockFileStreamFactory.cs b/TestingHelpers/MockFileStreamFactory.cs new file mode 100644 index 000000000..d6da9a855 --- /dev/null +++ b/TestingHelpers/MockFileStreamFactory.cs @@ -0,0 +1,83 @@ +using System.Security.AccessControl; +using Microsoft.Win32.SafeHandles; + +namespace System.IO.Abstractions.TestingHelpers +{ + [Serializable] + public class MockFileStreamFactory : IFileStreamFactory + { + private readonly IMockFileDataAccessor mockFileSystem; + + public MockFileStreamFactory(IMockFileDataAccessor mockFileSystem) + => this.mockFileSystem = mockFileSystem ?? throw new ArgumentNullException(nameof(mockFileSystem)); + + public Stream Create(string path, FileMode mode) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode)); + + public Stream Create(string path, FileMode mode, FileAccess access) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode, access)); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode, access)); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode, access)); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode, access)); + + public Stream Create(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode, access)); + +#if NET40 + public Stream Create(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity fileSecurity) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode)); + + public Stream Create(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options) + => new MockFileStream(mockFileSystem, path, GetStreamType(mode)); +#endif + +#if NET40 || NETSTANDARD_20 + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access) instead. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access) + => new MockFileStream(mockFileSystem, handle.ToString(), GetStreamType(FileMode.Append, access)); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access, bool ownsHandle) + => new MockFileStream(mockFileSystem, handle.ToString(), GetStreamType(FileMode.Append, access)); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access, int bufferSize) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize) + => new MockFileStream(mockFileSystem, handle.ToString(), GetStreamType(FileMode.Append, access)); + + [Obsolete("This method has been deprecated. Please use new Create(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")] + public Stream Create(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync) + => new MockFileStream(mockFileSystem, handle.ToString(), GetStreamType(FileMode.Append, access)); +#endif + + public Stream Create(SafeFileHandle handle, FileAccess access) + => new MockFileStream(mockFileSystem, handle.ToString(), GetStreamType(FileMode.Append, access)); + + public Stream Create(SafeFileHandle handle, FileAccess access, int bufferSize) + => new MockFileStream(mockFileSystem, handle.ToString(), GetStreamType(FileMode.Append, access)); + + public Stream Create(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) + => new MockFileStream(mockFileSystem, handle.ToString(), GetStreamType(FileMode.Append, access)); + + private static MockFileStream.StreamType GetStreamType(FileMode mode, FileAccess access = FileAccess.ReadWrite) + { + if (access == FileAccess.Read) + { + return MockFileStream.StreamType.READ; + } + else if (mode == FileMode.Append) + { + return MockFileStream.StreamType.APPEND; + } + else + { + return MockFileStream.StreamType.WRITE; + } + } + } +} \ No newline at end of file diff --git a/TestingHelpers/MockFileSystem.cs b/TestingHelpers/MockFileSystem.cs index df32754a2..50c493e3e 100644 --- a/TestingHelpers/MockFileSystem.cs +++ b/TestingHelpers/MockFileSystem.cs @@ -10,7 +10,6 @@ namespace System.IO.Abstractions.TestingHelpers public class MockFileSystem : IFileSystem, IMockFileDataAccessor { private readonly IDictionary files; - [NonSerialized] private readonly PathVerifier pathVerifier; @@ -26,10 +25,12 @@ public MockFileSystem(IDictionary files, string currentDir pathVerifier = new PathVerifier(this); this.files = new Dictionary(StringComparer.OrdinalIgnoreCase); + Path = new MockPath(this); File = new MockFile(this); Directory = new MockDirectory(this, File, currentDirectory); FileInfo = new MockFileInfoFactory(this); + FileStream = new MockFileStreamFactory(this); DirectoryInfo = new MockDirectoryInfoFactory(this); DriveInfo = new MockDriveInfoFactory(this); FileSystemWatcher = new MockFileSystemWatcherFactory(); @@ -49,6 +50,8 @@ public MockFileSystem(IDictionary files, string currentDir public IFileInfoFactory FileInfo { get; } + public IFileStreamFactory FileStream { get; } + public PathBase Path { get; } public IDirectoryInfoFactory DirectoryInfo { get; } diff --git a/TestingHelpers/TestingHelpers.csproj b/TestingHelpers/TestingHelpers.csproj index 73d0d556c..465a76a56 100644 --- a/TestingHelpers/TestingHelpers.csproj +++ b/TestingHelpers/TestingHelpers.csproj @@ -1,4 +1,4 @@ - + net40;netstandard1.4;netstandard2.0; System.IO.Abstractions.TestingHelpers