From defd44b682b3b4a240573ff78c6e43f16a079264 Mon Sep 17 00:00:00 2001 From: davidrogers090 <42214669+davidrogers090@users.noreply.github.com> Date: Mon, 15 Aug 2022 06:54:17 -0700 Subject: [PATCH] feat: add CreateSymbolicLink support (#871) * Adds CreateSymbolicLink support Adds a FileSystemInfo extension for wrapping convenience. Adds FEATURE_CREATE_SYMBOLIC_LINK to the build properties. Includes mock implementations and mock tests. Updates the ApiParityTests to no longer ignore CreateSymbolicLink for .net 6.0. Bumps the version in version.json. * Skip path tests on non-Windows platform Co-authored-by: Florian Greinacher --- Directory.Build.props | 2 +- .../MockDirectory.cs | 24 ++ .../MockFile.cs | 40 +++ src/System.IO.Abstractions/Converters.cs | 3 + src/System.IO.Abstractions/DirectoryBase.cs | 5 +- .../DirectoryWrapper.cs | 8 +- src/System.IO.Abstractions/FileBase.cs | 5 +- src/System.IO.Abstractions/FileWrapper.cs | 7 + src/System.IO.Abstractions/IDirectory.cs | 4 + src/System.IO.Abstractions/IFile.cs | 4 + .../MockDirectorySymlinkTests.cs | 206 +++++++++++++++ .../MockFileSymlinkTests.cs | 236 ++++++++++++++++++ .../ApiParityTests.Directory_.NET 6.0.snap | 1 - .../ApiParityTests.File_.NET 6.0.snap | 1 - version.json | 2 +- 15 files changed, 541 insertions(+), 7 deletions(-) create mode 100644 tests/System.IO.Abstractions.TestingHelpers.Tests/MockDirectorySymlinkTests.cs create mode 100644 tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileSymlinkTests.cs diff --git a/Directory.Build.props b/Directory.Build.props index 47f38d44c..7aca0706e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,7 @@ $(DefineConstants);FEATURE_FILE_SYSTEM_ACL_EXTENSIONS $(DefineConstants);FEATURE_ASYNC_FILE;FEATURE_ENUMERATION_OPTIONS;FEATURE_ADVANCED_PATH_OPERATIONS;FEATURE_PATH_JOIN_WITH_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 - $(DefineConstants);FEATURE_FILE_SYSTEM_INFO_LINK_TARGET + $(DefineConstants);FEATURE_FILE_SYSTEM_INFO_LINK_TARGET;FEATURE_CREATE_SYMBOLIC_LINK diff --git a/src/System.IO.Abstractions.TestingHelpers/MockDirectory.cs b/src/System.IO.Abstractions.TestingHelpers/MockDirectory.cs index 4cda23ef1..92e933f17 100644 --- a/src/System.IO.Abstractions.TestingHelpers/MockDirectory.cs +++ b/src/System.IO.Abstractions.TestingHelpers/MockDirectory.cs @@ -84,6 +84,30 @@ private IDirectoryInfo CreateDirectoryInternal(string path, DirectorySecurity di return created; } +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + public override IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget) + { + mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, nameof(path)); + mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(pathToTarget, nameof(pathToTarget)); + + if (Exists(path)) + { + throw CommonExceptions.FileAlreadyExists(nameof(path)); + } + + var targetExists = Exists(pathToTarget); + if (!targetExists) + { + throw CommonExceptions.FileNotFound(pathToTarget); + } + + mockFileDataAccessor.AddDirectory(path); + mockFileDataAccessor.GetFile(path).LinkTarget = pathToTarget; + + return new MockDirectoryInfo(mockFileDataAccessor, path); + } +#endif /// public override void Delete(string path) diff --git a/src/System.IO.Abstractions.TestingHelpers/MockFile.cs b/src/System.IO.Abstractions.TestingHelpers/MockFile.cs index a07c84501..32b52a871 100644 --- a/src/System.IO.Abstractions.TestingHelpers/MockFile.cs +++ b/src/System.IO.Abstractions.TestingHelpers/MockFile.cs @@ -155,6 +155,46 @@ private Stream CreateInternal(string path, FileAccess access, FileOptions option return OpenInternal(path, FileMode.Open, access, options); } +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + public override IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget) + { + if (path == null) + { + throw CommonExceptions.FilenameCannotBeNull(nameof(path)); + } + + if (pathToTarget == null) + { + throw CommonExceptions.FilenameCannotBeNull(nameof(pathToTarget)); + } + + mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, nameof(path)); + mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(pathToTarget, nameof(pathToTarget)); + + if (Exists(path)) + { + throw CommonExceptions.FileAlreadyExists(nameof(path)); + } + + VerifyDirectoryExists(path); + + var fileExists = mockFileDataAccessor.FileExists(pathToTarget); + if (!fileExists) + { + throw CommonExceptions.FileNotFound(pathToTarget); + } + + var sourceFileData = mockFileDataAccessor.GetFile(pathToTarget); + sourceFileData.CheckFileAccess(pathToTarget, FileAccess.Read); + var destFileData = new MockFileData(new byte[0]); + destFileData.CreationTime = destFileData.LastAccessTime = DateTime.Now; + destFileData.LinkTarget = pathToTarget; + mockFileDataAccessor.AddFile(path, destFileData); + + return new MockFileInfo(mockFileDataAccessor, path); + } +#endif /// public override StreamWriter CreateText(string path) { diff --git a/src/System.IO.Abstractions/Converters.cs b/src/System.IO.Abstractions/Converters.cs index 08d4ccd75..fe29c8d3f 100644 --- a/src/System.IO.Abstractions/Converters.cs +++ b/src/System.IO.Abstractions/Converters.cs @@ -12,6 +12,9 @@ internal static IEnumerable WrapFileSystemInfos(this IEnumer internal static FileSystemInfoBase[] WrapFileSystemInfos(this FileSystemInfo[] input, IFileSystem fileSystem) => input.Select(info => WrapFileSystemInfo(fileSystem, info)).ToArray(); + internal static FileSystemInfoBase WrapFileSystemInfo(this FileSystemInfo input, IFileSystem fileSystem) + => WrapFileSystemInfo(fileSystem, input); + internal static IEnumerable WrapDirectories(this IEnumerable input, IFileSystem fileSystem) => input.Select(info => WrapDirectoryInfo(fileSystem, info)); diff --git a/src/System.IO.Abstractions/DirectoryBase.cs b/src/System.IO.Abstractions/DirectoryBase.cs index 726832507..934a6f4ae 100644 --- a/src/System.IO.Abstractions/DirectoryBase.cs +++ b/src/System.IO.Abstractions/DirectoryBase.cs @@ -28,7 +28,10 @@ internal DirectoryBase() { } /// [SupportedOSPlatform("windows")] public abstract IDirectoryInfo CreateDirectory(string path, DirectorySecurity directorySecurity); - +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + public abstract IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget); +#endif /// public abstract void Delete(string path); diff --git a/src/System.IO.Abstractions/DirectoryWrapper.cs b/src/System.IO.Abstractions/DirectoryWrapper.cs index 75b38beb5..2830f22f2 100644 --- a/src/System.IO.Abstractions/DirectoryWrapper.cs +++ b/src/System.IO.Abstractions/DirectoryWrapper.cs @@ -29,7 +29,13 @@ public override IDirectoryInfo CreateDirectory(string path, DirectorySecurity di directoryInfo.Create(directorySecurity); return new DirectoryInfoWrapper(FileSystem, directoryInfo); } - +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + public override IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget) + { + return Directory.CreateSymbolicLink(path, pathToTarget).WrapFileSystemInfo(FileSystem); + } +#endif /// public override void Delete(string path) { diff --git a/src/System.IO.Abstractions/FileBase.cs b/src/System.IO.Abstractions/FileBase.cs index f3c583099..8b4c9d5c3 100644 --- a/src/System.IO.Abstractions/FileBase.cs +++ b/src/System.IO.Abstractions/FileBase.cs @@ -52,7 +52,10 @@ internal FileBase() { } /// public abstract Stream Create(string path, int bufferSize, FileOptions options); - +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + public abstract IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget); +#endif /// public abstract StreamWriter CreateText(string path); /// diff --git a/src/System.IO.Abstractions/FileWrapper.cs b/src/System.IO.Abstractions/FileWrapper.cs index 5ea9b8d1f..36c6fcb9f 100644 --- a/src/System.IO.Abstractions/FileWrapper.cs +++ b/src/System.IO.Abstractions/FileWrapper.cs @@ -75,6 +75,13 @@ public override Stream Create(string path, int bufferSize, FileOptions options) return File.Create(path, bufferSize, options); } +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + public override IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget) + { + return File.CreateSymbolicLink(path, pathToTarget).WrapFileSystemInfo(FileSystem); + } +#endif /// public override StreamWriter CreateText(string path) { diff --git a/src/System.IO.Abstractions/IDirectory.cs b/src/System.IO.Abstractions/IDirectory.cs index 7401ef446..d09a9cda4 100644 --- a/src/System.IO.Abstractions/IDirectory.cs +++ b/src/System.IO.Abstractions/IDirectory.cs @@ -20,6 +20,10 @@ public interface IDirectory /// #endif IDirectoryInfo CreateDirectory(string path, DirectorySecurity directorySecurity); +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget); +#endif /// void Delete(string path); /// diff --git a/src/System.IO.Abstractions/IFile.cs b/src/System.IO.Abstractions/IFile.cs index 2b9c40d78..e1d8e155d 100644 --- a/src/System.IO.Abstractions/IFile.cs +++ b/src/System.IO.Abstractions/IFile.cs @@ -33,6 +33,10 @@ public partial interface IFile Stream Create(string path, int bufferSize); /// Stream Create(string path, int bufferSize, FileOptions options); +#if FEATURE_CREATE_SYMBOLIC_LINK + /// + IFileSystemInfo CreateSymbolicLink(string path, string pathToTarget); +#endif /// StreamWriter CreateText(string path); /// diff --git a/tests/System.IO.Abstractions.TestingHelpers.Tests/MockDirectorySymlinkTests.cs b/tests/System.IO.Abstractions.TestingHelpers.Tests/MockDirectorySymlinkTests.cs new file mode 100644 index 000000000..1ca59848f --- /dev/null +++ b/tests/System.IO.Abstractions.TestingHelpers.Tests/MockDirectorySymlinkTests.cs @@ -0,0 +1,206 @@ +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Versioning; +using System.Security.AccessControl; +using NUnit.Framework; + +namespace System.IO.Abstractions.TestingHelpers.Tests +{ + using XFS = MockUnixSupport; + + [TestFixture] + public class MockDirectorySymlinkTests + { + +#if FEATURE_CREATE_SYMBOLIC_LINK + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldReturnFileSystemInfo() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo"); + var path = XFS.Path(@"C:\bar"); + fileSystem.AddDirectory(pathToTarget); + + // Act + IFileSystemInfo fileSystemInfo = fileSystem.Directory.CreateSymbolicLink(path, pathToTarget); + + // Assert + Assert.AreEqual(path, fileSystemInfo.FullName); + Assert.AreEqual(pathToTarget, fileSystemInfo.LinkTarget); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldSucceedFromDirectoryInfo() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo"); + var path = XFS.Path(@"C:\bar"); + fileSystem.AddDirectory(pathToTarget); + + // Act + fileSystem.Directory.CreateSymbolicLink(path, pathToTarget); + IDirectoryInfo directoryInfo = fileSystem.DirectoryInfo.FromDirectoryName(path); + + // Assert + Assert.AreEqual(path, directoryInfo.FullName); + Assert.AreEqual(pathToTarget, directoryInfo.LinkTarget); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithNullPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo"); + fileSystem.AddDirectory(pathToTarget); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink(null, pathToTarget)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("path")); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithNullTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + var path = XFS.Path(@"C:\Folder\foo"); + fileSystem.AddDirectory(path); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink(path, null)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("pathToTarget")); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithEmptyPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo"); + fileSystem.AddDirectory(pathToTarget); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink("", pathToTarget)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("path")); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithEmptyTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\Folder\foo"); + fileSystem.AddDirectory(path); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink(path, "")); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("pathToTarget")); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithIllegalPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + string pathToTarget = XFS.Path(@"C:\Folder\foo"); + fileSystem.AddDirectory(pathToTarget); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink(" ", pathToTarget)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("path")); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithIllegalTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\Folder\foo"); + fileSystem.AddDirectory(path); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink(path, " ")); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("pathToTarget")); + } + + [Test] + [WindowsOnly(WindowsSpecifics.StrictPathRules)] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithIllegalCharactersInPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + string pathToTarget = XFS.Path(@"C:\Folder\foo"); + fileSystem.AddDirectory(pathToTarget); + + // Act + TestDelegate ex = () => fileSystem.Directory.CreateSymbolicLink(@"C:\bar_?_", pathToTarget); + + // Assert + Assert.Throws(ex); + } + + [Test] + [WindowsOnly(WindowsSpecifics.StrictPathRules)] + public void MockDirectory_CreateSymbolicLink_ShouldFailWithIllegalCharactersInTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\foo"); + + // Act + TestDelegate ex = () => fileSystem.Directory.CreateSymbolicLink(path, @"C:\bar_?_"); + + // Assert + Assert.Throws(ex); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailIfPathExists() + { + // Arrange + var fileSystem = new MockFileSystem(); + string pathToTarget = XFS.Path(@"C:\Folder\foo"); + string path = XFS.Path(@"C:\Folder\bar"); + fileSystem.AddDirectory(pathToTarget); + fileSystem.AddDirectory(path); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink(path, pathToTarget)); + + // Assert + Assert.That(ex.Message.Contains("path")); + } + + [Test] + public void MockDirectory_CreateSymbolicLink_ShouldFailIfTargetDoesNotExist() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\Folder\foo"); + string pathToTarget = XFS.Path(@"C:\Target"); + + // Act + var ex = Assert.Throws(() => fileSystem.Directory.CreateSymbolicLink(path, pathToTarget)); + + // Assert + Assert.That(ex.Message.Contains(pathToTarget)); + } +#endif + } +} diff --git a/tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileSymlinkTests.cs b/tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileSymlinkTests.cs new file mode 100644 index 000000000..6f5f907dd --- /dev/null +++ b/tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileSymlinkTests.cs @@ -0,0 +1,236 @@ +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Versioning; +using System.Security.AccessControl; +using NUnit.Framework; + +namespace System.IO.Abstractions.TestingHelpers.Tests +{ + using XFS = MockUnixSupport; + + [TestFixture] + public class MockFileSymlinkTests + { + +#if FEATURE_CREATE_SYMBOLIC_LINK + + [Test] + public void MockFile_CreateSymbolicLink_ShouldReturnFileSystemInfo() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo.txt"); + var path = XFS.Path(@"C:\bar.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + + // Act + IFileSystemInfo fileSystemInfo = fileSystem.File.CreateSymbolicLink(path, pathToTarget); + + // Assert + Assert.AreEqual(path, fileSystemInfo.FullName); + Assert.AreEqual(pathToTarget, fileSystemInfo.LinkTarget); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldSucceedFromFileInfo() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo.txt"); + var path = XFS.Path(@"C:\bar.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + + // Act + fileSystem.File.CreateSymbolicLink(path, pathToTarget); + IFileInfo directoryInfo = fileSystem.FileInfo.FromFileName(path); + + // Assert + Assert.AreEqual(path, directoryInfo.FullName); + Assert.AreEqual(pathToTarget, directoryInfo.LinkTarget); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailWithNullPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(null, pathToTarget)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("path")); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailWithNullTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + var path = XFS.Path(@"C:\Folder\foo.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(path, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(path, null)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("pathToTarget")); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailWithEmptyPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + var pathToTarget = XFS.Path(@"C:\Folder\foo.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink("", pathToTarget)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("path")); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailWithEmptyTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\Folder\foo.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(path, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(path, "")); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("pathToTarget")); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailWithIllegalPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + string pathToTarget = XFS.Path(@"C:\Folder\foo.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(" ", pathToTarget)); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("path")); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailWithIllegalTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\Folder\foo.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(path, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(path, " ")); + + // Assert + Assert.That(ex.ParamName, Is.EqualTo("pathToTarget")); + } + + [Test] + [WindowsOnly(WindowsSpecifics.StrictPathRules)] + public void MockFile_CreateSymbolicLink_ShouldFailWithIllegalCharactersInPath() + { + // Arrange + var fileSystem = new MockFileSystem(); + string pathToTarget = XFS.Path(@"C:\Folder\foo.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + + // Act + TestDelegate ex = () => fileSystem.File.CreateSymbolicLink(@"C:\bar.txt_?_", pathToTarget); + + // Assert + Assert.Throws(ex); + } + + [Test] + [WindowsOnly(WindowsSpecifics.StrictPathRules)] + + public void MockFile_CreateSymbolicLink_ShouldFailWithIllegalCharactersInTarget() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\Folder\foo.txt"); + + // Act + TestDelegate ex = () => fileSystem.File.CreateSymbolicLink(path, @"C:\bar.txt_?_"); + + // Assert + Assert.Throws(ex); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailIfPathExists() + { + // Arrange + var fileSystem = new MockFileSystem(); + string pathToTarget = XFS.Path(@"C:\Folder\foo.txt"); + string path = XFS.Path(@"C:\Folder\bar.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + fileSystem.AddFile(path, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(path, pathToTarget)); + + // Assert + Assert.That(ex.Message.Contains("path")); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailIfTargetDoesNotExist() + { + // Arrange + var fileSystem = new MockFileSystem(); + string dir = XFS.Path(@"C:\Folder"); + string path = XFS.Path(@"C:\Folder\foo.txt"); + string pathToTarget = XFS.Path(@"C:\bar.txt"); + fileSystem.AddDirectory(dir); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(path, pathToTarget)); + + // Assert + Assert.That(ex.Message.Contains(pathToTarget)); + } + + [Test] + public void MockFile_CreateSymbolicLink_ShouldFailIfPathDirectoryDoesNotExist() + { + // Arrange + var fileSystem = new MockFileSystem(); + string path = XFS.Path(@"C:\Folder\foo.txt"); + string pathToTarget = XFS.Path(@"C:\bar.txt"); + var data = new MockFileData("foobar"); + fileSystem.AddFile(pathToTarget, data); + + // Act + var ex = Assert.Throws(() => fileSystem.File.CreateSymbolicLink(path, pathToTarget)); + + // Assert + Assert.That(ex.Message.Contains(path)); + } +#endif + } +} diff --git a/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.Directory_.NET 6.0.snap b/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.Directory_.NET 6.0.snap index 8f3eba16a..9def4d0c1 100644 --- a/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.Directory_.NET 6.0.snap +++ b/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.Directory_.NET 6.0.snap @@ -6,7 +6,6 @@ "Void SetAccessControl(System.String, System.Security.AccessControl.DirectorySecurity)" ], "MissingMembers": [ - "System.IO.Abstractions.IFileSystemInfo CreateSymbolicLink(System.String, System.String)", "System.IO.Abstractions.IFileSystemInfo ResolveLinkTarget(System.String, Boolean)", "System.String[] GetFileSystemEntries(System.String, System.String, System.IO.EnumerationOptions)", "System.String[] GetFileSystemEntries(System.String, System.String, System.IO.SearchOption)" diff --git a/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.File_.NET 6.0.snap b/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.File_.NET 6.0.snap index df8565435..542f05d5f 100644 --- a/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.File_.NET 6.0.snap +++ b/tests/System.IO.Abstractions.Tests/__snapshots__/ApiParityTests.File_.NET 6.0.snap @@ -9,7 +9,6 @@ "MissingMembers": [ "Microsoft.Win32.SafeHandles.SafeFileHandle OpenHandle(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, System.IO.FileOptions, Int64)", "System.IO.Stream Open(System.String, System.IO.StreamOptions)", - "System.IO.Abstractions.IFileSystemInfo CreateSymbolicLink(System.String, System.String)", "System.IO.Abstractions.IFileSystemInfo ResolveLinkTarget(System.String, Boolean)" ] } diff --git a/version.json b/version.json index f1fe92c5d..0515ee918 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "17.0", + "version": "17.1", "assemblyVersion": { "precision": "major" },