diff --git a/docs/api/VFSException.VFSException(string).md b/docs/api/VFSException.VFSException(string).md
new file mode 100644
index 0000000..8ffd435
--- /dev/null
+++ b/docs/api/VFSException.VFSException(string).md
@@ -0,0 +1,17 @@
+#### [Atypical.VirtualFileSystem.Core](VirtualFileSystem.md 'VirtualFileSystem')
+### [Atypical.VirtualFileSystem.Core.Exceptions](VirtualFileSystem.md#Atypical.VirtualFileSystem.Core.Exceptions 'Atypical.VirtualFileSystem.Core.Exceptions').[VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException')
+
+## VFSException(string) Constructor
+
+Initializes a new instance of the [VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException') class with a message that describes the error.
+
+```csharp
+public VFSException(string message);
+```
+#### Parameters
+
+
+
+`message` [System.String](https://docs.microsoft.com/en-us/dotnet/api/System.String 'System.String')
+
+The error message that explains the reason for the exception.
\ No newline at end of file
diff --git a/docs/api/VFSException.VFSException(string,Exception).md b/docs/api/VFSException.VFSException(string,Exception).md
new file mode 100644
index 0000000..a45cc84
--- /dev/null
+++ b/docs/api/VFSException.VFSException(string,Exception).md
@@ -0,0 +1,25 @@
+#### [Atypical.VirtualFileSystem.Core](VirtualFileSystem.md 'VirtualFileSystem')
+### [Atypical.VirtualFileSystem.Core.Exceptions](VirtualFileSystem.md#Atypical.VirtualFileSystem.Core.Exceptions 'Atypical.VirtualFileSystem.Core.Exceptions').[VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException')
+
+## VFSException(string, Exception) Constructor
+
+Initializes a new instance of the [VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException') class with a message and an inner exception that is the cause
+of this exception.
+
+```csharp
+public VFSException(string message, System.Exception innerException);
+```
+#### Parameters
+
+
+
+`message` [System.String](https://docs.microsoft.com/en-us/dotnet/api/System.String 'System.String')
+
+The error message that explains the reason for the exception.
+
+
+
+`innerException` [System.Exception](https://docs.microsoft.com/en-us/dotnet/api/System.Exception 'System.Exception')
+
+The exception that is the cause of the current exception, or a null reference if no inner
+exception is specified.
\ No newline at end of file
diff --git a/docs/api/VFSException.md b/docs/api/VFSException.md
new file mode 100644
index 0000000..09670dc
--- /dev/null
+++ b/docs/api/VFSException.md
@@ -0,0 +1,17 @@
+#### [Atypical.VirtualFileSystem.Core](VirtualFileSystem.md 'VirtualFileSystem')
+### [Atypical.VirtualFileSystem.Core.Exceptions](VirtualFileSystem.md#Atypical.VirtualFileSystem.Core.Exceptions 'Atypical.VirtualFileSystem.Core.Exceptions')
+
+## VFSException Class
+
+Exception thrown by the VFS.
+
+```csharp
+public class VFSException : System.Exception
+```
+
+Inheritance [System.Object](https://docs.microsoft.com/en-us/dotnet/api/System.Object 'System.Object') 🡒 [System.Exception](https://docs.microsoft.com/en-us/dotnet/api/System.Exception 'System.Exception') 🡒 VFSException
+
+| Constructors | |
+| :--- | :--- |
+| [VFSException(string, Exception)](VFSException.VFSException(string,Exception).md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException.VFSException(string, System.Exception)') | Initializes a new instance of the [VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException') class with a message and an inner exception that is the cause
of this exception. |
+| [VFSException(string)](VFSException.VFSException(string).md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException.VFSException(string)') | Initializes a new instance of the [VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException') class with a message that describes the error. |
diff --git a/docs/api/VirtualFileSystem.md b/docs/api/VirtualFileSystem.md
index 623bb40..04bdc71 100644
--- a/docs/api/VirtualFileSystem.md
+++ b/docs/api/VirtualFileSystem.md
@@ -200,6 +200,14 @@
For example, the path of the node with the path "./temp/file.txt" is "./temp/file.txt".
The path of the node with the path "./temp/" is "./temp/".
+
+
+## Atypical.VirtualFileSystem.Core.Exceptions Namespace
+- **[VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException')** `Class` Exception thrown by the VFS.
+ - **[VFSException(string, Exception)](VFSException.VFSException(string,Exception).md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException.VFSException(string, System.Exception)')** `Constructor` Initializes a new instance of the [VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException') class with a message and an inner exception that is the cause
+ of this exception.
+ - **[VFSException(string)](VFSException.VFSException(string).md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException.VFSException(string)')** `Constructor` Initializes a new instance of the [VFSException](VFSException.md 'Atypical.VirtualFileSystem.Core.Exceptions.VFSException') class with a message that describes the error.
+
## Atypical.VirtualFileSystem.Core.Models Namespace
diff --git a/docs/links b/docs/links
index e3102d8..5bb7e7a 100644
--- a/docs/links
+++ b/docs/links
@@ -71,6 +71,10 @@ T:Atypical.VirtualFileSystem.Core.Models.FileNode|FileNode.md|FileNode
M:Atypical.VirtualFileSystem.Core.Models.RootNode.#ctor|RootNode.RootNode().md|RootNode()
M:Atypical.VirtualFileSystem.Core.Models.RootNode.ToString|RootNode.ToString().md|ToString()
T:Atypical.VirtualFileSystem.Core.Models.RootNode|RootNode.md|RootNode
+M:Atypical.VirtualFileSystem.Core.Exceptions.VFSException.#ctor(System.String)|VFSException.VFSException(string).md|VFSException(string)
+M:Atypical.VirtualFileSystem.Core.Exceptions.VFSException.#ctor(System.String,System.Exception)|VFSException.VFSException(string,Exception).md|VFSException(string, Exception)
+N:Atypical.VirtualFileSystem.Core.Exceptions|VirtualFileSystem.md#Atypical.VirtualFileSystem.Core.Exceptions|Atypical.VirtualFileSystem.Core.Exceptions
+T:Atypical.VirtualFileSystem.Core.Exceptions.VFSException|VFSException.md|VFSException
N:Atypical.VirtualFileSystem.Core.Contracts|VirtualFileSystem.md#Atypical.VirtualFileSystem.Core.Contracts|Atypical.VirtualFileSystem.Core.Contracts
T:Atypical.VirtualFileSystem.Core.Contracts.IDirectoryNode|IDirectoryNode.md|IDirectoryNode
P:Atypical.VirtualFileSystem.Core.Contracts.IFileNode.Content|IFileNode.Content.md|Content
diff --git a/src/Atypical.VirtualFileSystem.Core/Abstractions/VFSPath.cs b/src/Atypical.VirtualFileSystem.Core/Abstractions/VFSPath.cs
index ceddade..d442312 100644
--- a/src/Atypical.VirtualFileSystem.Core/Abstractions/VFSPath.cs
+++ b/src/Atypical.VirtualFileSystem.Core/Abstractions/VFSPath.cs
@@ -22,6 +22,8 @@ public abstract record VFSPath
///
public static readonly Regex VFSPathRegex = new(VFSPathRegexPattern, RegexOptions.Compiled);
+
+
///
/// Creates a new instance of .
///
@@ -30,7 +32,9 @@ public abstract record VFSPath
/// Thrown when the path is invalid.
public VFSPath(string path)
{
- ArgumentNullException.ThrowIfNull(path);
+ // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
+ if (path is null)
+ ThrowArgumentHasInvalidFormat(string.Empty);
var vfsPath = CleanVFSPathInput(path);
@@ -41,11 +45,11 @@ public VFSPath(string path)
return;
}
- if (!VFSPathRegex.IsMatch(vfsPath))
- throw new ArgumentException($"The path '{path}' is invalid.", nameof(path));
-
if (vfsPath.Contains($".{DIRECTORY_SEPARATOR}") || vfsPath.Contains($"{DIRECTORY_SEPARATOR}."))
- throw new ArgumentException($"The path '{path}' contains relative path segments.", nameof(path));
+ ThrowArgumentHasRelativePathSegment(vfsPath);
+
+ if (!VFSPathRegex.IsMatch(vfsPath))
+ ThrowArgumentHasInvalidFormat(vfsPath);
Value = vfsPath;
@@ -143,6 +147,9 @@ private string CleanVFSPathInput(string path)
// if is root path, return it
if (cleanPath is ROOT_PATH or "")
return cleanPath;
+
+ // replace backslashes with forward slashes
+ cleanPath = cleanPath.Replace('\\', '/');
// clean up the path - remove leading and trailing slashes
cleanPath = cleanPath.TrimStart('/');
@@ -167,8 +174,7 @@ private string CleanVFSPathInput(string path)
public VFSPath GetAbsoluteParentPath(int depthFromRoot)
{
if (depthFromRoot < 0)
- throw new ArgumentOutOfRangeException(nameof(depthFromRoot),
- "The depth from root must be greater than or equal to 0.");
+ ThrowDepthFromRootMustBeGreaterThanOrEqualToZero(depthFromRoot);
if (IsRoot)
return this;
@@ -184,4 +190,33 @@ public VFSPath GetAbsoluteParentPath(int depthFromRoot)
///
/// A hash code for the current object.
public override int GetHashCode() => Value.GetHashCode();
-}
\ No newline at end of file
+
+ [DoesNotReturn]
+ private static void ThrowArgumentHasRelativePathSegment(string vfsPath)
+ {
+ var message = $"The path '{vfsPath}' contains a relative path segment.";
+ throw new VFSException(message, new ArgumentException(message));
+ }
+
+ [DoesNotReturn]
+ private static void ThrowArgumentHasInvalidFormat(string vfsPath)
+ {
+ var message = vfsPath.Length > 0
+ ? $"The path '{vfsPath}' is invalid."
+ : "An empty path is invalid.";
+
+ throw new VFSException(message, new ArgumentException(message));
+ }
+
+ [DoesNotReturn]
+ private static void ThrowDepthFromRootMustBeGreaterThanOrEqualToZero(int depthFromRoot)
+ {
+ var message = $"""
+ The depth from root must be greater than or equal to 0.
+ Actual value: {depthFromRoot}.
+ """;
+
+ throw new VFSException(message);
+ }
+}
+
diff --git a/src/Atypical.VirtualFileSystem.Core/Atypical.VirtualFileSystem.Core.csproj.DotSettings b/src/Atypical.VirtualFileSystem.Core/Atypical.VirtualFileSystem.Core.csproj.DotSettings
new file mode 100644
index 0000000..61bfa61
--- /dev/null
+++ b/src/Atypical.VirtualFileSystem.Core/Atypical.VirtualFileSystem.Core.csproj.DotSettings
@@ -0,0 +1,3 @@
+
+ True
+ True
\ No newline at end of file
diff --git a/src/Atypical.VirtualFileSystem.Core/Exceptions/VFSException.cs b/src/Atypical.VirtualFileSystem.Core/Exceptions/VFSException.cs
new file mode 100644
index 0000000..2a8cc71
--- /dev/null
+++ b/src/Atypical.VirtualFileSystem.Core/Exceptions/VFSException.cs
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, Atypical Consulting SRL
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+namespace Atypical.VirtualFileSystem.Core.Exceptions;
+
+///
+/// Exception thrown by the VFS.
+///
+public class VFSException : Exception
+{
+ ///
+ /// Initializes a new instance of the class with a message that describes the error.
+ ///
+ /// The error message that explains the reason for the exception.
+ public VFSException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a message and an inner exception that is the cause
+ /// of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ ///
+ /// The exception that is the cause of the current exception, or a null reference if no inner
+ /// exception is specified.
+ ///
+ public VFSException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Atypical.VirtualFileSystem.Core/GlobalUsings.cs b/src/Atypical.VirtualFileSystem.Core/GlobalUsings.cs
index 9bce44d..35077d9 100644
--- a/src/Atypical.VirtualFileSystem.Core/GlobalUsings.cs
+++ b/src/Atypical.VirtualFileSystem.Core/GlobalUsings.cs
@@ -12,6 +12,7 @@
global using System.Text.RegularExpressions;
global using Atypical.VirtualFileSystem.Core.Abstractions;
global using Atypical.VirtualFileSystem.Core.Contracts;
+global using Atypical.VirtualFileSystem.Core.Exceptions;
global using Atypical.VirtualFileSystem.Core.Models;
global using Atypical.VirtualFileSystem.Core.ValueObjects;
global using static Atypical.VirtualFileSystem.Core.VFSConstants;
\ No newline at end of file
diff --git a/src/Atypical.VirtualFileSystem.Core/VFS.cs b/src/Atypical.VirtualFileSystem.Core/VFS.cs
index a4edb98..d715bb4 100644
--- a/src/Atypical.VirtualFileSystem.Core/VFS.cs
+++ b/src/Atypical.VirtualFileSystem.Core/VFS.cs
@@ -39,7 +39,7 @@ private void AddToIndex(IVirtualFileSystemNode node)
var added = Index.TryAdd(node.Path.Value, node);
if (!added)
- throw new InvalidOperationException($"The node '{node.Path}' already exists in the index.");
+ ThrowVirtualNodeAlreadyExists(node);
if (node.Path.Parent is not null && !Index.ContainsKey(node.Path.Parent.Value))
CreateDirectory(node.Path.Parent);
@@ -135,7 +135,7 @@ public bool TryGetDirectory(string path, out IDirectoryNode? directory)
public IVirtualFileSystem CreateDirectory(VFSDirectoryPath directoryPath)
{
if (directoryPath.IsRoot)
- throw new ArgumentException("Cannot create root directory.", nameof(directoryPath));
+ ThrowCannotCreateRootDirectory();
var directory = new DirectoryNode(directoryPath);
AddToIndex(directory);
@@ -150,12 +150,12 @@ public IVirtualFileSystem CreateDirectory(string path)
public IVirtualFileSystem DeleteDirectory(VFSDirectoryPath directoryPath)
{
if (directoryPath.IsRoot)
- throw new ArgumentException("Cannot delete root directory.", nameof(directoryPath));
+ ThrowCannotDeleteRootDirectory();
// try to get the directory
var found = TryGetDirectory(directoryPath, out _);
if (!found)
- throw new KeyNotFoundException($"The directory '{directoryPath}' does not exist.");
+ ThrowVirtualDirectoryNotFound(directoryPath);
// find the path and its children in the index
var paths = Index.Keys
@@ -231,7 +231,7 @@ public IVirtualFileSystem DeleteFile(VFSFilePath filePath)
// try to get the file
var found = TryGetFile(filePath, out _);
if (!found)
- throw new KeyNotFoundException($"The file '{filePath}' does not exist.");
+ ThrowVirtualFileNotFound(filePath);
// remove the file from the index
Index.Remove(filePath.Value);
@@ -252,4 +252,39 @@ public IEnumerable FindFiles(Regex regexPattern)
=> FindFiles().Where(f => regexPattern.IsMatch(f.Path.Value));
#endregion
+
+ [DoesNotReturn]
+ private static void ThrowVirtualNodeAlreadyExists(IVirtualFileSystemNode node)
+ {
+ var message = $"The node '{node.Path}' already exists in the index.";
+ throw new VFSException(message);
+ }
+
+ [DoesNotReturn]
+ private static void ThrowVirtualFileNotFound(VFSFilePath filePath)
+ {
+ var message = $"The file '{filePath}' does not exist in the index.";
+ throw new VFSException(message);
+ }
+
+ [DoesNotReturn]
+ private static void ThrowVirtualDirectoryNotFound(VFSDirectoryPath directoryPath)
+ {
+ var message = $"The directory '{directoryPath}' does not exist in the index.";
+ throw new VFSException(message);
+ }
+
+ [DoesNotReturn]
+ private static void ThrowCannotDeleteRootDirectory()
+ {
+ const string message = "Cannot delete the root directory.";
+ throw new VFSException(message);
+ }
+
+ [DoesNotReturn]
+ private static void ThrowCannotCreateRootDirectory()
+ {
+ const string message = "Cannot create the root directory.";
+ throw new VFSException(message);
+ }
}
diff --git a/src/Atypical.VirtualFileSystem.Core/ValueObjects/VFSDirectoryPath.cs b/src/Atypical.VirtualFileSystem.Core/ValueObjects/VFSDirectoryPath.cs
index 7ea7790..b5abfd7 100644
--- a/src/Atypical.VirtualFileSystem.Core/ValueObjects/VFSDirectoryPath.cs
+++ b/src/Atypical.VirtualFileSystem.Core/ValueObjects/VFSDirectoryPath.cs
@@ -24,7 +24,7 @@ public VFSDirectoryPath(string path)
// cannot ends with a file extension
var lastSegment = Value.Split('/').Last();
if (lastSegment.Contains('.'))
- throw new ArgumentException("The path must not contain a file extension.", nameof(path));
+ ThrowArgumentHasFileExtension(path);
}
///
@@ -41,4 +41,11 @@ public VFSDirectoryPath(string path)
/// The path to convert.
/// The string representation of the path.
public static implicit operator string(VFSDirectoryPath path) => path.Value;
+
+ [DoesNotReturn]
+ private static void ThrowArgumentHasFileExtension(string path)
+ {
+ var message = $"The directory path '{path}' contains a file extension.";
+ throw new VFSException(message, new ArgumentException(message));
+ }
}
\ No newline at end of file
diff --git a/tests/Atypical.VirtualFileSystem.UnitTests/GlobalUsings.cs b/tests/Atypical.VirtualFileSystem.UnitTests/GlobalUsings.cs
index 05b11b8..c34f193 100644
--- a/tests/Atypical.VirtualFileSystem.UnitTests/GlobalUsings.cs
+++ b/tests/Atypical.VirtualFileSystem.UnitTests/GlobalUsings.cs
@@ -7,6 +7,7 @@
// Global using directives
global using Atypical.VirtualFileSystem.Core;
+global using Atypical.VirtualFileSystem.Core.Exceptions;
global using Atypical.VirtualFileSystem.Core.Models;
global using Atypical.VirtualFileSystem.Core.ValueObjects;
global using FluentAssertions;
diff --git a/tests/Atypical.VirtualFileSystem.UnitTests/Models/VirtualFileSystemTests.cs b/tests/Atypical.VirtualFileSystem.UnitTests/Models/VirtualFileSystemTests.cs
index 9fe4060..ef6fa88 100644
--- a/tests/Atypical.VirtualFileSystem.UnitTests/Models/VirtualFileSystemTests.cs
+++ b/tests/Atypical.VirtualFileSystem.UnitTests/Models/VirtualFileSystemTests.cs
@@ -164,7 +164,9 @@ public void CreateDirectory_throws_an_exception_if_the_directory_already_exists(
Action action = () => vfs.CreateDirectory(directoryPath);
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage($"The node 'vfs://dir1' already exists in the index.");
}
[Fact]
@@ -179,7 +181,9 @@ public void CreateDirectory_throws_an_exception_if_the_path_is_not_a_directory()
Action action = () => vfs.CreateDirectory(filePath);
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The directory path 'vfs://dir1/dir2/dir3/file.txt' contains a file extension.");
}
}
@@ -226,7 +230,9 @@ public void DeleteDirectory_throws_an_exception_if_the_directory_does_not_exist(
Action action = () => vfs.DeleteDirectory(directoryPath);
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The directory 'vfs://dir1' does not exist in the index.");
}
}
@@ -368,7 +374,9 @@ public void CreateFile_throws_an_exception_if_the_file_already_exists()
Action action = () => vfs.CreateFile(filePath);
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The node 'vfs://dir1/dir2/dir3/file.txt' already exists in the index.");
}
}
@@ -399,7 +407,9 @@ public void DeleteFile_throws_an_exception_if_the_file_does_not_exist()
Action action = () => vfs.DeleteFile("dir1/dir2/dir3/file.txt");
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The file 'vfs://dir1/dir2/dir3/file.txt' does not exist in the index.");
}
}
diff --git a/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSDirectoryPathTests.cs b/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSDirectoryPathTests.cs
index 039f913..39804b1 100644
--- a/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSDirectoryPathTests.cs
+++ b/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSDirectoryPathTests.cs
@@ -17,7 +17,7 @@ public class Constructor
// - The path must not contain any consecutive slashes (//).
[Fact]
- public void Constructor_throw_ArgumentNullException_when_path_is_null()
+ public void Constructor_throw_VFSException_when_path_is_null()
{
// Arrange
const string path = null!;
@@ -29,11 +29,13 @@ public void Constructor_throw_ArgumentNullException_when_path_is_null()
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("An empty path is invalid.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_is_empty()
+ public void Constructor_throw_VFSException_when_path_is_empty()
{
// Arrange
const string path = "";
@@ -45,27 +47,13 @@ public void Constructor_throw_ArgumentException_when_path_is_empty()
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("An empty path is invalid.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_contains_invalid_characters()
- {
- // Arrange
- const string path = @"invalid\path";
-
- // Act
- var action = () =>
- {
- var _ = new VFSDirectoryPath(path);
- };
-
- // Assert
- action.Should().Throw();
- }
-
- [Fact]
- public void Constructor_throw_ArgumentException_when_path_contains_relative_path_segments()
+ public void Constructor_throw_VFSException_when_path_contains_relative_path_segments()
{
// Arrange
const string path = @"invalid\..\path";
@@ -77,11 +65,13 @@ public void Constructor_throw_ArgumentException_when_path_contains_relative_path
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The path 'vfs://invalid/../path' contains a relative path segment.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_contains_consecutive_slashes()
+ public void Constructor_throw_VFSException_when_path_contains_consecutive_slashes()
{
// Arrange
const string path = @"invalid//path";
@@ -93,11 +83,13 @@ public void Constructor_throw_ArgumentException_when_path_contains_consecutive_s
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The path 'vfs://invalid//path' is invalid.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_is_not_a_directory_path()
+ public void Constructor_throw_VFSException_when_path_is_not_a_directory_path()
{
// Arrange
const string path = @"invalid/path.txt";
@@ -109,7 +101,9 @@ public void Constructor_throw_ArgumentException_when_path_is_not_a_directory_pat
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The directory path 'invalid/path.txt' contains a file extension.");
}
[Fact]
diff --git a/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSFilePathTests.cs b/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSFilePathTests.cs
index fbeefab..e1e3ea6 100644
--- a/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSFilePathTests.cs
+++ b/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSFilePathTests.cs
@@ -18,7 +18,7 @@ public class Constructor
// - The path must not end with a slash (/).
[Fact]
- public void Constructor_throw_ArgumentNullException_when_path_is_null()
+ public void Constructor_throw_VFSException_when_path_is_null()
{
// Arrange
const string path = null!;
@@ -30,11 +30,13 @@ public void Constructor_throw_ArgumentNullException_when_path_is_null()
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("An empty path is invalid.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_is_empty()
+ public void Constructor_throw_VFSException_when_path_is_empty()
{
// Arrange
const string path = "";
@@ -46,23 +48,9 @@ public void Constructor_throw_ArgumentException_when_path_is_empty()
};
// Assert
- action.Should().Throw();
- }
-
- [Fact]
- public void Constructor_throw_ArgumentException_when_path_contains_invalid_characters()
- {
- // Arrange
- const string path = @"invalid\path";
-
- // Act
- var action = () =>
- {
- var _ = new VFSFilePath(path);
- };
-
- // Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("An empty path is invalid.");
}
}
diff --git a/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSPathTest.cs b/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSPathTest.cs
index 5ba751a..8d6fefe 100644
--- a/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSPathTest.cs
+++ b/tests/Atypical.VirtualFileSystem.UnitTests/ValueObjects/VFSPathTest.cs
@@ -18,7 +18,7 @@ public class Constructor
// - The path must not end with a slash (/).
[Fact]
- public void Constructor_throw_ArgumentNullException_when_path_is_null()
+ public void Constructor_throw_VFSException_when_path_is_null()
{
// Arrange
const string path = null!;
@@ -30,11 +30,13 @@ public void Constructor_throw_ArgumentNullException_when_path_is_null()
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("An empty path is invalid.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_is_empty()
+ public void Constructor_throw_VFSException_when_path_is_empty()
{
// Arrange
const string path = "";
@@ -46,27 +48,13 @@ public void Constructor_throw_ArgumentException_when_path_is_empty()
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("An empty path is invalid.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_contains_invalid_characters()
- {
- // Arrange
- const string path = @"invalid\path";
-
- // Act
- var action = () =>
- {
- var _ = new VFSDirectoryPath(path);
- };
-
- // Assert
- action.Should().Throw();
- }
-
- [Fact]
- public void Constructor_throw_ArgumentException_when_path_contains_relative_path_segments()
+ public void Constructor_throw_VFSException_when_path_contains_relative_path_segments()
{
// Arrange
const string path = @"invalid/../path";
@@ -78,11 +66,13 @@ public void Constructor_throw_ArgumentException_when_path_contains_relative_path
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The path 'vfs://invalid/../path' contains a relative path segment.");
}
[Fact]
- public void Constructor_throw_ArgumentException_when_path_contains_consecutive_slashes()
+ public void Constructor_throw_VFSException_when_path_contains_consecutive_slashes()
{
// Arrange
const string path = @"invalid//path";
@@ -94,7 +84,9 @@ public void Constructor_throw_ArgumentException_when_path_contains_consecutive_s
};
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage("The path 'vfs://invalid//path' is invalid.");
}
[Fact]
@@ -337,7 +329,7 @@ public void MethodGetAbsoluteParentPath_return_root_when_path_is_root()
}
[Fact]
- public void MethodGetAbsoluteParentPath_throw_exception_when_depth_is_negative()
+ public void MethodGetAbsoluteParentPath_throw_VFSException_when_depth_is_negative()
{
// Arrange
const string path = @"directory/subdirectory";
@@ -347,7 +339,12 @@ public void MethodGetAbsoluteParentPath_throw_exception_when_depth_is_negative()
Action action = () => vfsPath.GetAbsoluteParentPath(-1);
// Assert
- action.Should().Throw();
+ action.Should()
+ .Throw()
+ .WithMessage($"""
+ The depth from root must be greater than or equal to 0.
+ Actual value: {-1}.
+ """);
}
[Fact]