diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f32f28..6c2f5f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added - X10D: Added `MathUtility.InverseLerp(float, float, float)` and `MathUtility.InverseLerp(double, double, double)` - X10D: Added `Circle`, `CircleF`, `Cuboid`, `Ellipse`, `EllipseF`, `Line3D`, `Line`, `LineF`, `Polygon`, `PolygonF`, `Polyhedron`, and `Sphere`, to complement System.Drawing structs such as `Point` and `Rectangle` +- X10D: Added `DirectoryInfo.Clear([bool])` - X10D: Added `IList.RemoveRange(Range)` - X10D: Added `Point.ToSize()` - X10D: Added `Point.ToSizeF()` diff --git a/X10D.Tests/src/IO/DirectoryInfoTests.cs b/X10D.Tests/src/IO/DirectoryInfoTests.cs new file mode 100644 index 0000000..375289d --- /dev/null +++ b/X10D.Tests/src/IO/DirectoryInfoTests.cs @@ -0,0 +1,83 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.IO; + +namespace X10D.Tests.IO; + +[TestClass] +public class DirectoryInfoTests +{ + [TestMethod] + public void Clear_ShouldClear_GivenValidDirectory() + { + string tempPath = Path.GetTempPath(); + DirectoryInfo directory; + do + { + string tempDirectory = Path.Combine(tempPath, Guid.NewGuid().ToString()); + directory = new DirectoryInfo(tempDirectory); + } while (directory.Exists); + + directory.Create(); + Assert.IsTrue(directory.Exists); + + var file = new FileInfo(Path.Combine(directory.FullName, "file")); + file.Create().Close(); + + var childDirectory = new DirectoryInfo(Path.Combine(directory.FullName, "child")); + childDirectory.Create(); + + var childFile = new FileInfo(Path.Combine(childDirectory.FullName, "childFile")); + childFile.Create().Close(); + + Assert.AreEqual(1, directory.GetFiles().Length); + Assert.AreEqual(1, directory.GetDirectories().Length); + directory.Clear(false); + Assert.AreEqual(0, directory.GetFiles().Length); + Assert.AreEqual(0, directory.GetDirectories().Length); + Assert.IsTrue(directory.Exists); + + directory.Delete(); + } + + [TestMethod] + public void Clear_ShouldDoNothing_GivenNonExistentDirectory() + { + var directory = new DirectoryInfo(@"/@12#3"); + Assert.IsFalse(directory.Exists); + directory.Clear(); + } + + [TestMethod] + public void Clear_ShouldNotThrow_WhenThrowOnErrorIsFalse() + { + var directory = new DirectoryInfo(@"/@12#3"); + Assert.IsFalse(directory.Exists); + + directory.Clear(); + directory.Clear(false); + + Assert.IsTrue(true); // if this assertion passes, then the test passed + } + + [TestMethod] + public void Clear_ShouldThrowArgumentNullException_GivenNull() + { + Assert.ThrowsException(() => ((DirectoryInfo?)null)!.Clear()); + Assert.ThrowsException(() => ((DirectoryInfo?)null)!.Clear(true)); + } + + [TestMethod] + public void Clear_ShouldThrowDirectoryNotFoundException_GivenInvalidDirectory() + { + var directory = new DirectoryInfo(@"123:/@12#3"); + Assert.ThrowsException(() => directory.Clear(true)); + } + + [TestMethod] + public void Clear_ShouldThrowDirectoryNotFoundException_GivenNonExistentDirectory() + { + var directory = new DirectoryInfo(@"/@12#3"); + Assert.IsFalse(directory.Exists); + Assert.ThrowsException(() => directory.Clear(true)); + } +} diff --git a/X10D/src/IO/DirectoryInfoExtensions.cs b/X10D/src/IO/DirectoryInfoExtensions.cs new file mode 100644 index 0000000..5613a66 --- /dev/null +++ b/X10D/src/IO/DirectoryInfoExtensions.cs @@ -0,0 +1,107 @@ +using System.Security; + +namespace X10D.IO; + +/// +/// IO-related extension methods for . +/// +public static class DirectoryInfoExtensions +{ + /// + /// Removes all files and subdirectories in this directory, recursively, without deleting this directory. + /// + /// The directory to clear. + public static void Clear(this DirectoryInfo directory) + { + directory.Clear(false); + } + + /// + /// Removes all files and subdirectories in this directory, recursively, without deleting this directory. + /// + /// The directory to clear. + /// + /// to throw any exceptions which were caught during the operation; otherwise, + /// + /// + /// + /// The directory described by this object does not exist or could not be found. This + /// exception is not thrown if is . + /// + /// + /// A target file is open or memory-mapped on a computer running Microsoft Windows NT. + /// -or- + /// There is an open handle on one of the files, and the operating system is Windows XP or earlier. This open handle can + /// result from enumerating directories and files. + /// -or- + /// The directory is read-only. + /// -or- + /// The directory contains one or more files or subdirectories and recursive is false. + /// -or- + /// The directory is the application's current working directory. + /// -or- + /// There is an open handle on the directory or on one of its files, and the operating system is Windows XP or earlier. + /// This open handle can result from enumerating directories and files. + /// This exception is not thrown if is . + /// + /// + /// The caller does not have the required permission. This exception is not thrown if is + /// . + /// + /// This directory or one of its children contain a read-only file. This + /// exception is not thrown if is . + /// + public static void Clear(this DirectoryInfo directory, bool throwOnError) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(directory); +#else + if (directory is null) + { + throw new ArgumentNullException(nameof(directory)); + } +#endif + + if (!directory.Exists) + { + if (throwOnError) + { + throw new DirectoryNotFoundException(); + } + + return; + } + + foreach (FileInfo file in directory.EnumerateFiles()) + { + try + { + file.Delete(); + } + catch when (throwOnError) + { + throw; + } + catch + { + // do nothing + } + } + + foreach (DirectoryInfo childDirectory in directory.EnumerateDirectories()) + { + try + { + childDirectory.Delete(true); + } + catch when (throwOnError) + { + throw; + } + catch + { + // do nothing + } + } + } +}