diff --git a/Source/Testably.Abstractions.FluentAssertions/DirectoryAssertions.cs b/Source/Testably.Abstractions.FluentAssertions/DirectoryAssertions.cs
index 88fcc48..9de56b5 100644
--- a/Source/Testably.Abstractions.FluentAssertions/DirectoryAssertions.cs
+++ b/Source/Testably.Abstractions.FluentAssertions/DirectoryAssertions.cs
@@ -17,36 +17,45 @@ internal DirectoryAssertions(IDirectoryInfo? instance)
}
///
- /// Asserts that the directory contains exactly one file matching the given .
+ /// Asserts that the current directory has at least directories which match the
+ /// .
///
- public AndWhichConstraint HasSingleFileMatching(
- string searchPattern = "*", string because = "", params object[] becauseArgs)
+ public AndConstraint HasDirectoriesMatching(
+ string searchPattern = "*",
+ int minimumCount = 1,
+ string because = "",
+ params object[] becauseArgs)
{
Execute.Assertion
.WithDefaultIdentifier(Identifier)
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert a directory having a given file if it is null")
+ "You can't assert a directory having directories if the DirectoryInfo is null.")
.Then
.ForCondition(!string.IsNullOrEmpty(searchPattern))
.FailWith(
- "You can't assert a directory having a given file if you don't pass a proper name")
+ "You can't assert a directory having directories if you don't pass a proper search pattern.")
.Then
.Given(() => Subject!)
.ForCondition(directoryInfo
- => directoryInfo.GetFiles(searchPattern).Length == 1)
+ => directoryInfo.GetDirectories(searchPattern).Length >= minimumCount)
.FailWith(
- "Expected {context} {1} to contain exactly one file matching {0}{reason}, but found {2}.",
+ $"Expected {{context}} {{1}} to contain at least {(minimumCount == 1 ? "one directory" : $"{minimumCount} directories")} matching {{0}}{{reason}}, but {(minimumCount == 1 ? "none was" : "only {2} were")} found.",
_ => searchPattern,
directoryInfo => directoryInfo.Name,
- directoryInfo => directoryInfo.GetFiles(searchPattern).Length);
-
- return new AndWhichConstraint(
- new FileSystemAssertions(Subject!.FileSystem),
- new FileAssertions(Subject!.GetFiles(searchPattern).Single()));
+ directoryInfo => directoryInfo.GetDirectories(searchPattern).Length);
+
+ return new AndConstraint(this);
}
+ ///
+ /// Asserts that the current directory has at least one directory which matches the .
+ ///
+ public AndConstraint HasDirectoryMatching(
+ string searchPattern = "*", string because = "", params object[] becauseArgs)
+ => HasDirectoriesMatching(searchPattern, 1, because, becauseArgs);
+
///
/// Asserts that the current directory has at least one file which matches the .
///
@@ -69,11 +78,11 @@ public AndConstraint HasFilesMatching(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert a directory having files if the DirectoryInfo is null")
+ "You can't assert a directory having files if the DirectoryInfo is null.")
.Then
.ForCondition(!string.IsNullOrEmpty(searchPattern))
.FailWith(
- "You can't assert a directory having files if you don't pass a proper name")
+ "You can't assert a directory having files if you don't pass a proper search pattern.")
.Then
.Given(() => Subject!)
.ForCondition(directoryInfo
@@ -86,4 +95,66 @@ public AndConstraint HasFilesMatching(
return new AndConstraint(this);
}
+
+ ///
+ /// Asserts that the directory contains exactly one directory matching the given .
+ ///
+ public AndWhichConstraint HasSingleDirectoryMatching(
+ string searchPattern = "*", string because = "", params object[] becauseArgs)
+ {
+ Execute.Assertion
+ .WithDefaultIdentifier(Identifier)
+ .BecauseOf(because, becauseArgs)
+ .ForCondition(Subject != null)
+ .FailWith(
+ "You can't assert a directory having a given directory if it is null.")
+ .Then
+ .ForCondition(!string.IsNullOrEmpty(searchPattern))
+ .FailWith(
+ "You can't assert a directory having a given directory if you don't pass a proper search pattern.")
+ .Then
+ .Given(() => Subject!)
+ .ForCondition(directoryInfo
+ => directoryInfo.GetDirectories(searchPattern).Length == 1)
+ .FailWith(
+ "Expected {context} {1} to contain exactly one directory matching {0}{reason}, but found {2}.",
+ _ => searchPattern,
+ directoryInfo => directoryInfo.Name,
+ directoryInfo => directoryInfo.GetDirectories(searchPattern).Length);
+
+ return new AndWhichConstraint(
+ new FileSystemAssertions(Subject!.FileSystem),
+ new DirectoryAssertions(Subject!.GetDirectories(searchPattern).Single()));
+ }
+
+ ///
+ /// Asserts that the directory contains exactly one file matching the given .
+ ///
+ public AndWhichConstraint HasSingleFileMatching(
+ string searchPattern = "*", string because = "", params object[] becauseArgs)
+ {
+ Execute.Assertion
+ .WithDefaultIdentifier(Identifier)
+ .BecauseOf(because, becauseArgs)
+ .ForCondition(Subject != null)
+ .FailWith(
+ "You can't assert a directory having a given file if it is null.")
+ .Then
+ .ForCondition(!string.IsNullOrEmpty(searchPattern))
+ .FailWith(
+ "You can't assert a directory having a given file if you don't pass a proper search pattern.")
+ .Then
+ .Given(() => Subject!)
+ .ForCondition(directoryInfo
+ => directoryInfo.GetFiles(searchPattern).Length == 1)
+ .FailWith(
+ "Expected {context} {1} to contain exactly one file matching {0}{reason}, but found {2}.",
+ _ => searchPattern,
+ directoryInfo => directoryInfo.Name,
+ directoryInfo => directoryInfo.GetFiles(searchPattern).Length);
+
+ return new AndWhichConstraint(
+ new FileSystemAssertions(Subject!.FileSystem),
+ new FileAssertions(Subject!.GetFiles(searchPattern).Single()));
+ }
}
diff --git a/Source/Testably.Abstractions.FluentAssertions/DirectoryInfoAssertions.cs b/Source/Testably.Abstractions.FluentAssertions/DirectoryInfoAssertions.cs
index 4575f7e..eb0d9ae 100644
--- a/Source/Testably.Abstractions.FluentAssertions/DirectoryInfoAssertions.cs
+++ b/Source/Testably.Abstractions.FluentAssertions/DirectoryInfoAssertions.cs
@@ -14,6 +14,16 @@ internal DirectoryInfoAssertions(IDirectoryInfo? instance)
{
}
+ ///
+ /// Asserts that the current directory has at least one directory which matches the .
+ ///
+ public AndConstraint HaveDirectoryMatching(
+ string searchPattern = "*", string because = "", params object[] becauseArgs)
+ {
+ new DirectoryAssertions(Subject).HasDirectoryMatching(searchPattern, because, becauseArgs);
+ return new AndConstraint(this);
+ }
+
///
/// Asserts that the current directory has at least one file which matches the .
///
@@ -24,12 +34,23 @@ public AndConstraint HaveFileMatching(
return new AndConstraint(this);
}
+ ///
+ /// Asserts that the directory contains exactly one directory matching the given .
+ ///
+ public AndWhichConstraint HaveSingleDirectory(
+ string searchPattern = "*", string because = "", params object[] becauseArgs)
+ {
+ return new DirectoryAssertions(Subject).HasSingleDirectoryMatching(searchPattern, because,
+ becauseArgs);
+ }
+
///
/// Asserts that the directory contains exactly one file matching the given .
///
public AndWhichConstraint HaveSingleFile(
string searchPattern = "*", string because = "", params object[] becauseArgs)
{
- return new DirectoryAssertions(Subject).HasSingleFileMatching(searchPattern, because, becauseArgs);
+ return new DirectoryAssertions(Subject).HasSingleFileMatching(searchPattern, because,
+ becauseArgs);
}
}
diff --git a/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs b/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs
index f898883..ff843c1 100644
--- a/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs
+++ b/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs
@@ -29,7 +29,7 @@ public AndConstraint DoesNotHaveAttribute(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- $"You can't assert that the file does not have attribute {attribute} if it is null")
+ $"You can't assert that the file does not have attribute {attribute} if it is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => !fileInfo.Attributes.HasFlag(attribute))
@@ -51,7 +51,7 @@ public AndConstraint HasAttribute(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- $"You can't assert that the file has attribute {attribute} if it is null")
+ $"You can't assert that the file has attribute {attribute} if it is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => fileInfo.Attributes.HasFlag(attribute))
@@ -73,7 +73,7 @@ public AndConstraint HasContent(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert the content of a file if the FileInfo is null")
+ "You can't assert the content of a file if the FileInfo is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => fileInfo.FileSystem.File
@@ -97,7 +97,7 @@ public AndConstraint HasContent(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert the content of a file if the FileInfo is null")
+ "You can't assert the content of a file if the FileInfo is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => pattern.Matches(
@@ -121,7 +121,7 @@ public AndConstraint HasContent(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert the content of a file if the FileInfo is null")
+ "You can't assert the content of a file if the FileInfo is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => pattern.Matches(
@@ -144,7 +144,7 @@ public AndConstraint IsNotReadOnly(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert that the file is not read-only if it is null")
+ "You can't assert that the file is not read-only if it is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => !fileInfo.IsReadOnly)
@@ -166,7 +166,7 @@ public AndConstraint IsReadOnly(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert that the file is read-only if it is null")
+ "You can't assert that the file is read-only if it is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => fileInfo.IsReadOnly)
diff --git a/Source/Testably.Abstractions.FluentAssertions/FileSystemAssertions.cs b/Source/Testably.Abstractions.FluentAssertions/FileSystemAssertions.cs
index eaa1e38..666081b 100644
--- a/Source/Testably.Abstractions.FluentAssertions/FileSystemAssertions.cs
+++ b/Source/Testably.Abstractions.FluentAssertions/FileSystemAssertions.cs
@@ -24,7 +24,7 @@ public AndWhichConstraint HaveDirecto
.WithDefaultIdentifier(Identifier)
.BecauseOf(because, becauseArgs)
.ForCondition(!string.IsNullOrEmpty(path))
- .FailWith("You can't assert that a directory exists if you don't pass a proper name.")
+ .FailWith("You can't assert that a directory exists if you don't pass a proper path.")
.Then
.Given(() => Subject.DirectoryInfo.New(path))
.ForCondition(directoryInfo => directoryInfo.Exists)
@@ -46,7 +46,7 @@ public AndWhichConstraint HaveFile(
.WithDefaultIdentifier(Identifier)
.BecauseOf(because, becauseArgs)
.ForCondition(!string.IsNullOrEmpty(path))
- .FailWith("You can't assert that a file exists if you don't pass a proper name.")
+ .FailWith("You can't assert that a file exists if you don't pass a proper path.")
.Then
.Given(() => Subject.FileInfo.New(path))
.ForCondition(fileInfo => fileInfo.Exists)
@@ -69,7 +69,7 @@ public AndWhichConstraint NotHaveDire
.BecauseOf(because, becauseArgs)
.ForCondition(!string.IsNullOrEmpty(path))
.FailWith(
- "You can't assert that a directory does not exist if you don't pass a proper name.")
+ "You can't assert that a directory does not exist if you don't pass a proper path.")
.Then
.Given(() => Subject.DirectoryInfo.New(path))
.ForCondition(directoryInfo => !directoryInfo.Exists)
@@ -92,7 +92,7 @@ public AndWhichConstraint NotHaveFile(
.BecauseOf(because, becauseArgs)
.ForCondition(!string.IsNullOrEmpty(path))
.FailWith(
- "You can't assert that a file does not exist if you don't pass a proper name.")
+ "You can't assert that a file does not exist if you don't pass a proper path.")
.Then
.Given(() => Subject.FileInfo.New(path))
.ForCondition(fileInfo => !fileInfo.Exists)
diff --git a/Source/Testably.Abstractions.FluentAssertions/FileSystemInfoAssertions.cs b/Source/Testably.Abstractions.FluentAssertions/FileSystemInfoAssertions.cs
index 4018a91..546c73b 100644
--- a/Source/Testably.Abstractions.FluentAssertions/FileSystemInfoAssertions.cs
+++ b/Source/Testably.Abstractions.FluentAssertions/FileSystemInfoAssertions.cs
@@ -26,7 +26,7 @@ public AndConstraint Exist(
.WithDefaultIdentifier(Identifier)
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
- .FailWith("You can't assert that the {context} exists if it is null")
+ .FailWith("You can't assert that the {context} exists if it is null.")
.Then
.Given(() => Subject!)
.ForCondition(fileSystemInfo => fileSystemInfo.Exists)
diff --git a/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryAssertionsTests.cs b/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryAssertionsTests.cs
index 50dfbf2..a99e119 100644
--- a/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryAssertionsTests.cs
+++ b/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryAssertionsTests.cs
@@ -8,6 +8,98 @@ namespace Testably.Abstractions.FluentAssertions.Tests;
public class DirectoryAssertionsTests
{
+ [Theory]
+ [InlineAutoData(3, 5)]
+ [InlineAutoData(1, 2)]
+ public void HasDirectoriesMatching_WithoutTooLittleDirectories_ShouldThrow(
+ int matchingCount,
+ int expectedCount,
+ string directoryName,
+ string directoryNamePrefix,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName);
+ for (int i = 0; i < matchingCount; i++)
+ {
+ fileSystem.Directory.CreateDirectory(
+ fileSystem.Path.Combine(directoryName, $"{directoryNamePrefix}-{i}"));
+ }
+
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory(directoryName).Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.HasDirectoriesMatching($"{directoryNamePrefix}*", expectedCount, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected directory \"{directoryName}\" to contain at least {expectedCount} directories matching \"{directoryNamePrefix}*\" {because}, but only {matchingCount} were found.");
+ }
+
+ [Theory]
+ [InlineAutoData(null)]
+ [InlineAutoData("")]
+ public void HasDirectoryMatching_InvalidDirectoryName_ShouldThrow(string? invalidDirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory("foo");
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory("foo").Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.HasDirectoryMatching(invalidDirectoryName!, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().NotBeNullOrEmpty();
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HasDirectoryMatching_WithMatchingDirectory_ShouldNotThrow(
+ string directoryName,
+ string subdirectoryName)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory(subdirectoryName));
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory(directoryName).Which;
+
+ sut.HasDirectoryMatching(subdirectoryName);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HasDirectoryMatching_WithoutMatchingDirectory_ShouldThrow(
+ string directoryName,
+ string subdirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory("not-matching-directory"));
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory(directoryName).Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.HasDirectoryMatching(subdirectoryName, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected directory \"{directoryName}\" to contain at least one directory matching \"{subdirectoryName}\" {because}, but none was found.");
+ }
+
[Theory]
[InlineAutoData(null)]
[InlineAutoData("")]
@@ -100,6 +192,92 @@ public void HasFilesMatching_WithoutTooLittleFiles_ShouldThrow(
$"Expected directory \"{directoryName}\" to contain at least {expectedCount} files matching \"{fileNamePrefix}*\" {because}, but only {matchingCount} were found.");
}
+ [Theory]
+ [InlineAutoData(null)]
+ [InlineAutoData("")]
+ public void HasSingleDirectoryMatching_InvalidDirectoryName_ShouldThrow(
+ string? invalidDirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory("foo");
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory("foo").Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.HasSingleDirectoryMatching(invalidDirectoryName!, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().NotBeNullOrEmpty();
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HasSingleDirectoryMatching_WithMatchingDirectory_ShouldNotThrow(
+ string directoryName,
+ string subdirectoryName)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory(subdirectoryName));
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory(directoryName).Which;
+
+ sut.HasSingleDirectoryMatching(subdirectoryName);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HasSingleDirectoryMatching_WithMultipleMatchingDirectory_ShouldThrow(
+ string directoryName,
+ string subdirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory($"{subdirectoryName}-1.txt")
+ .WithSubdirectory($"{subdirectoryName}-2.txt"));
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory(directoryName).Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.HasSingleDirectoryMatching($"{subdirectoryName}*", because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected directory \"{directoryName}\" to contain exactly one directory matching \"{subdirectoryName}*\" {because}, but found 2.");
+ }
+
+ [Theory]
+ [AutoData]
+ public void HasSingleDirectoryMatching_WithoutMatchingDirectory_ShouldThrow(
+ string directoryName,
+ string subdirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory("not-matching-directory"));
+ DirectoryAssertions? sut = fileSystem.Should().HaveDirectory(directoryName).Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.HasSingleDirectoryMatching(subdirectoryName, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected directory \"{directoryName}\" to contain exactly one directory matching \"{subdirectoryName}\" {because}, but found 0.");
+ }
+
[Theory]
[InlineAutoData(null)]
[InlineAutoData("")]
diff --git a/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryInfoAssertionsTests.cs b/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryInfoAssertionsTests.cs
index f1fbf60..7cd0a80 100644
--- a/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryInfoAssertionsTests.cs
+++ b/Tests/Testably.Abstractions.FluentAssertions.Tests/DirectoryInfoAssertionsTests.cs
@@ -9,6 +9,82 @@ namespace Testably.Abstractions.FluentAssertions.Tests;
public class DirectoryInfoAssertionsTests
{
+ [Theory]
+ [InlineAutoData(null)]
+ [InlineAutoData("")]
+ public void HaveDirectoryMatching_InvalidDirectoryName_ShouldThrow(string? invalidDirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory("foo");
+ IDirectoryInfo sut = fileSystem.DirectoryInfo.New("foo");
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveDirectoryMatching(invalidDirectoryName!, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().NotBeNullOrEmpty();
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveDirectoryMatching_Null_ShouldThrow(string because)
+ {
+ IDirectoryInfo? sut = null;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveDirectoryMatching(because: because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().Contain("null");
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveDirectoryMatching_WithMatchingDirectory_ShouldNotThrow(
+ string directoryName,
+ string subdirectoryName)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory(subdirectoryName));
+ IDirectoryInfo sut = fileSystem.DirectoryInfo.New(directoryName);
+
+ sut.Should().HaveDirectoryMatching(subdirectoryName);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveDirectoryMatching_WithoutMatchingDirectory_ShouldThrow(
+ string directoryName,
+ string subdirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory("not-matching-directory"));
+ IDirectoryInfo sut = fileSystem.DirectoryInfo.New(directoryName);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveDirectoryMatching(subdirectoryName, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected directory \"{directoryName}\" to contain at least one directory matching \"{subdirectoryName}\" {because}, but none was found.");
+ }
+
[Theory]
[InlineAutoData(null)]
[InlineAutoData("")]
@@ -85,6 +161,106 @@ public void HaveFileMatching_WithoutMatchingFile_ShouldThrow(
$"Expected directory \"{directoryName}\" to contain at least one file matching \"{fileName}\" {because}, but none was found.");
}
+ [Theory]
+ [InlineAutoData(null)]
+ [InlineAutoData("")]
+ public void HaveSingleDirectory_InvalidDirectoryName_ShouldThrow(string? invalidDirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory("foo");
+ IDirectoryInfo sut = fileSystem.DirectoryInfo.New("foo");
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveSingleDirectory(invalidDirectoryName!, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().NotBeNullOrEmpty();
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveSingleDirectory_Null_ShouldThrow(string because)
+ {
+ IDirectoryInfo? sut = null;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveSingleDirectory(because: because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().Contain("null");
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveSingleDirectory_WithMatchingDirectory_ShouldNotThrow(
+ string directoryName,
+ string subdirectoryName)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory(subdirectoryName));
+ IDirectoryInfo sut = fileSystem.DirectoryInfo.New(directoryName);
+
+ sut.Should().HaveSingleDirectory(subdirectoryName);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveSingleDirectory_WithMultipleMatchingDirectory_ShouldThrow(
+ string directoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory("directory1.txt")
+ .WithSubdirectory("directory2.txt"));
+ IDirectoryInfo sut = fileSystem.DirectoryInfo.New(directoryName);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveSingleDirectory("directory*.txt", because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected directory \"{directoryName}\" to contain exactly one directory matching \"directory*.txt\" {because}, but found 2.");
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveSingleDirectory_WithoutMatchingDirectory_ShouldThrow(
+ string directoryName,
+ string subdirectoryName,
+ string because)
+ {
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .WithSubdirectory(directoryName).Initialized(d => d
+ .WithSubdirectory("not-matching-directory"));
+ IDirectoryInfo sut = fileSystem.DirectoryInfo.New(directoryName);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveSingleDirectory(subdirectoryName, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected directory \"{directoryName}\" to contain exactly one directory matching \"{subdirectoryName}\" {because}, but found 0.");
+ }
+
[Theory]
[InlineAutoData(null)]
[InlineAutoData("")]