Index: Core/Common/test/Core.Common.TestUtil.Test/DirectoryDisposeHelperTest.cs =================================================================== diff -u -r3a1d4488d68236efe6eccbd60be3484735aa689b -ref03645b89161cd4351b386fd664acc27a5e1408 --- Core/Common/test/Core.Common.TestUtil.Test/DirectoryDisposeHelperTest.cs (.../DirectoryDisposeHelperTest.cs) (revision 3a1d4488d68236efe6eccbd60be3484735aa689b) +++ Core/Common/test/Core.Common.TestUtil.Test/DirectoryDisposeHelperTest.cs (.../DirectoryDisposeHelperTest.cs) (revision ef03645b89161cd4351b386fd664acc27a5e1408) @@ -128,10 +128,6 @@ Assert.DoesNotThrow(test); disposeHelper.Dispose(); } - catch (Exception exception) - { - Assert.Fail(exception.Message); - } finally { if (Directory.Exists(folderPath)) @@ -147,10 +143,10 @@ [TestCase("valid", "/fo:der/")] [TestCase("f*lder", "valid")] [TestCase("valid", "f*lder")] - public void Constructor_InvalidFolderPath_ThrowsArgumentException(string rootFolder, string subfolder) + public void Constructor_InvalidFolderPath_ThrowsArgumentException(string someRootFolder, string subfolder) { // Call - TestDelegate test = () => new DirectoryDisposeHelper(rootFolder, subfolder); + TestDelegate test = () => new DirectoryDisposeHelper(someRootFolder, subfolder); // Assert Assert.Throws(test); @@ -210,7 +206,7 @@ disposeHelper.LockDirectory(FileSystemRights.Write); // Assert - Assert.IsFalse(IsDirectoryWritable(folderPath), $"'{folderPath}' is not locked for writing."); + Assert.IsFalse(TestHelper.CanWriteInDirectory(folderPath), $"'{folderPath}' should have been locked for writing."); } Assert.IsFalse(Directory.Exists(folderPath), $"'{folderPath}' should have been deleted."); @@ -276,38 +272,107 @@ RemoveDirectoryAndFail(folderPath, exception); } } - - private static void RemoveDirectoryAndFail(string folderPath, Exception exception) + + [Test] + public void UnlockDirectory_DirectoryNotLocked_Unlocksdirectory() { + // Setup + string subfolder = nameof(UnlockDirectory_DirectoryNotLocked_Unlocksdirectory); + string folderPath = Path.Combine(rootFolder, subfolder); + + using (var disposeHelper = new DirectoryDisposeHelper(rootFolder, subfolder)) + { + // Call + TestDelegate test = () => disposeHelper.UnlockDirectory(); + + // Assert + string actualMessage = Assert.Throws(test).Message; + Assert.AreEqual($"Directory '{folderPath}' is not locked.", actualMessage); + } + try { - Directory.Delete(folderPath); + Assert.IsFalse(Directory.Exists(folderPath), $"'{folderPath}' should have been deleted."); } - catch + catch (Exception exception) { - // Ignore + RemoveDirectoryAndFail(folderPath, exception); } - Assert.Fail(exception.Message, exception.InnerException); } - private static bool IsDirectoryWritable(string folderPath) + [Test] + public void UnlockDirectory_DirectoryLocked_Unlocksdirectory() { - string filePath = Path.Combine(folderPath, Path.GetRandomFileName()); + // Setup + string subfolder = nameof(UnlockDirectory_DirectoryLocked_Unlocksdirectory); + string folderPath = Path.Combine(rootFolder, subfolder); + + using (var disposeHelper = new DirectoryDisposeHelper(rootFolder, subfolder)) + { + disposeHelper.LockDirectory(FileSystemRights.Write); + + // Call + disposeHelper.UnlockDirectory(); + + // Assert + TestDelegate createFile = () => + { + using (File.Create(folderPath)) {} + }; + Assert.Throws(createFile); + } + try { - using (File.OpenWrite(filePath)) {} + bool exists = Directory.Exists(folderPath); + Assert.IsFalse(exists, $"'{folderPath}' should have been deleted."); } - catch (SystemException) + catch (Exception exception) { - return false; + RemoveDirectoryAndFail(folderPath, exception); } + } - if (File.Exists(filePath)) + [Test] + public void UnlockDirectory_DirectoryAlreadyUnlocked_DoesNotThrowException() + { + // Setup + string subfolder = nameof(UnlockDirectory_DirectoryAlreadyUnlocked_DoesNotThrowException); + string folderPath = Path.Combine(rootFolder, subfolder); + + try { - File.Delete(filePath); + using (var disposeHelper = new DirectoryDisposeHelper(rootFolder, subfolder)) + { + disposeHelper.LockDirectory(FileSystemRights.Write); + disposeHelper.UnlockDirectory(); + + // Call + TestDelegate call = () => disposeHelper.UnlockDirectory(); + + // Assert + Assert.DoesNotThrow(call); + } + + Assert.IsFalse(Directory.Exists(folderPath), $"'{folderPath}' should have been deleted."); } + catch (Exception exception) + { + RemoveDirectoryAndFail(folderPath, exception); + } + } - return true; + private static void RemoveDirectoryAndFail(string folderPath, Exception exception) + { + try + { + Directory.Delete(folderPath); + } + catch + { + // Ignore + } + Assert.Fail(exception.Message, exception.InnerException); } } } \ No newline at end of file Index: Core/Common/test/Core.Common.TestUtil.Test/TestHelperTest.cs =================================================================== diff -u -rd18995d638a6c3f99cb7a8419107bb4148420301 -ref03645b89161cd4351b386fd664acc27a5e1408 --- Core/Common/test/Core.Common.TestUtil.Test/TestHelperTest.cs (.../TestHelperTest.cs) (revision d18995d638a6c3f99cb7a8419107bb4148420301) +++ Core/Common/test/Core.Common.TestUtil.Test/TestHelperTest.cs (.../TestHelperTest.cs) (revision ef03645b89161cd4351b386fd664acc27a5e1408) @@ -22,6 +22,8 @@ using System; using System.Drawing; using System.IO; +using System.Security.AccessControl; +using System.Threading; using System.Windows.Forms; using Core.Common.TestUtil.Test.Properties; using log4net; @@ -35,9 +37,9 @@ private static readonly ILog log = LogManager.GetLogger(typeof(TestHelperTest)); [Test] - public void CanOpenFileForWrite_InvalidPath_DoesNotThrowAnyExceptions() + public void CanOpenFileForWrite_PathDoesNotExist_DoesNotThrowAnyExceptions() { - const string invalidPath = @".\DirectoryDoesNotExist\fileDoesNotExist"; + const string invalidPath = @".\DirectoryDoesotExist\fileDoesNotExist"; var canOpenForWrite = true; // Call @@ -80,6 +82,76 @@ } [Test] + public void CanWriteInDirectory_PathNull_ThrowsArgumentNullException() + { + // Call + TestDelegate call = () => TestHelper.CanWriteInDirectory(null); + + // Assert + Assert.Throws(call); + } + + [Test] + public void CanWriteInDirectory_InvalidDirectory_ThrowsArgumentException() + { + // Setup + char[] invalidPathChars = Path.GetInvalidPathChars(); + string invalidPath = $"f*l{invalidPathChars[2]}er"; + + // Call + TestDelegate call = () => TestHelper.CanWriteInDirectory(invalidPath); + + // Assert + Assert.Throws(call); + } + + [Test] + public void CanWriteInDirectory_DirectoryDoesNotExist_ReturnsFalse() + { + // Setup + string validPath = Path.Combine(TestHelper.GetScratchPadPath(), nameof(CanWriteInDirectory_CanWriteInDirectory_ReturnsTrue)); + + // Call + bool canWrite = TestHelper.CanWriteInDirectory(validPath); + + // Assert + Assert.IsFalse(canWrite); + } + + [Test] + public void CanWriteInDirectory_CanWriteInDirectory_ReturnsTrue() + { + // Setup + using (new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), nameof(CanWriteInDirectory_CanWriteInDirectory_ReturnsTrue))) + { + string validPath = TestHelper.GetScratchPadPath(nameof(CanWriteInDirectory_CanWriteInDirectory_ReturnsTrue)); + + // Call + bool canWrite = TestHelper.CanWriteInDirectory(validPath); + + // Assert + Assert.IsTrue(canWrite); + } + } + + [Test] + public void CanWriteInDirectory_CanNotWriteInDirectory_ReturnsFalse() + { + // Setup + using (var helper = new DirectoryDisposeHelper(TestHelper.GetScratchPadPath(), nameof(CanWriteInDirectory_CanWriteInDirectory_ReturnsTrue))) + { + string validPath = TestHelper.GetScratchPadPath(nameof(CanWriteInDirectory_CanWriteInDirectory_ReturnsTrue)); + helper.LockDirectory(FileSystemRights.Write); + + // Call + bool canWrite = TestHelper.CanWriteInDirectory(validPath); + + // Assert + Assert.IsFalse(canWrite); + } + } + + [Test] public void GetScratchPadPath_WithoutPath_ReturnRootFolder() { // Call @@ -93,15 +165,16 @@ } [Test] + [Apartment(ApartmentState.STA)] public void GetScratchPadPath_WithoutPathAndFolderDoesntExist_ThrowIOException() { // Setup - string actualPath = TestHelper.GetScratchPadPath(); + string actualPath = Path.Combine(Path.GetDirectoryName(TestHelper.SolutionRoot), "Scratchpad"); - Directory.Delete(actualPath, true); - try { + Directory.Delete(actualPath, true); + // Call TestDelegate call = () => TestHelper.GetScratchPadPath(); Index: Core/Common/test/Core.Common.TestUtil/DirectoryDisposeHelper.cs =================================================================== diff -u -rf02614d781e389e05b9b481e8d165286e6baad4d -ref03645b89161cd4351b386fd664acc27a5e1408 --- Core/Common/test/Core.Common.TestUtil/DirectoryDisposeHelper.cs (.../DirectoryDisposeHelper.cs) (revision f02614d781e389e05b9b481e8d165286e6baad4d) +++ Core/Common/test/Core.Common.TestUtil/DirectoryDisposeHelper.cs (.../DirectoryDisposeHelper.cs) (revision ef03645b89161cd4351b386fd664acc27a5e1408) @@ -72,11 +72,11 @@ /// /// Adds a of type to the access - /// rule set for the folder at . + /// rule set for the folder at the set directory path. /// /// The right to deny. /// Thrown when the directory could not be locked. - /// + /// The lock is removed when disposing the instance. public void LockDirectory(FileSystemRights rights) { try @@ -89,6 +89,19 @@ } } + /// + /// Unlocks the directory that was locked by . + /// + /// Thrown when the directory was not locked. + public void UnlockDirectory() + { + if (directoryPermissionsRevoker == null) + { + throw new InvalidOperationException($"Directory '{rootPathToTemp}' is not locked."); + } + directoryPermissionsRevoker.Dispose(); + } + public void Dispose() { Dispose(true); @@ -102,7 +115,10 @@ return; } - directoryPermissionsRevoker?.Dispose(); + if (disposing) + { + directoryPermissionsRevoker?.Dispose(); + } var directoryDeleted = false; try @@ -115,11 +131,6 @@ // ignored } - if (disposing) - { - directoryPermissionsRevoker = null; - } - disposed = !directoryDeleted; } Index: Core/Common/test/Core.Common.TestUtil/FileDisposeHelper.cs =================================================================== diff -u -r27a3de13b3b94459fc79664d521de3790dd6b0df -ref03645b89161cd4351b386fd664acc27a5e1408 --- Core/Common/test/Core.Common.TestUtil/FileDisposeHelper.cs (.../FileDisposeHelper.cs) (revision 27a3de13b3b94459fc79664d521de3790dd6b0df) +++ Core/Common/test/Core.Common.TestUtil/FileDisposeHelper.cs (.../FileDisposeHelper.cs) (revision ef03645b89161cd4351b386fd664acc27a5e1408) @@ -75,6 +75,7 @@ /// /// Thrown when one of the files could not be locked. /// + /// Files are unlocked when disposing the instance. public void LockFiles() { IEnumerable> notLockedFiles = filePathStreams.Where(f => f.Value == null).ToArray(); Index: Core/Common/test/Core.Common.TestUtil/TestHelper.cs =================================================================== diff -u -rd18995d638a6c3f99cb7a8419107bb4148420301 -ref03645b89161cd4351b386fd664acc27a5e1408 --- Core/Common/test/Core.Common.TestUtil/TestHelper.cs (.../TestHelper.cs) (revision d18995d638a6c3f99cb7a8419107bb4148420301) +++ Core/Common/test/Core.Common.TestUtil/TestHelper.cs (.../TestHelper.cs) (revision ef03645b89161cd4351b386fd664acc27a5e1408) @@ -106,23 +106,43 @@ /// true if the file could be opened with write permissions. false otherwise. public static bool CanOpenFileForWrite(string pathToFile) { - FileStream file = null; try { - file = File.OpenWrite(pathToFile); + using (File.OpenWrite(pathToFile)) {} return true; } catch (IOException) { return false; } - finally + } + + /// + /// Checks whether the directory pointed at by can be used + /// for writing a file. + /// + /// The location of the directory to open for writing. + /// true if the file could be opened with write permissions. false otherwise. + /// Thrown when is null. + /// Thrown when contains invalid characters. + public static bool CanWriteInDirectory(string pathToDirectory) + { + string filePath = Path.Combine(pathToDirectory, nameof(CanWriteInDirectory)); + try { - if (file != null) - { - file.Close(); - } + using (File.OpenWrite(filePath)){} } + catch (SystemException) + { + return false; + } + + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + + return true; } ///