Skip to content

Commit bd22c57

Browse files
authored
feat: add assertions for HasDirectoriesMatching (#42)
Add assertions on a `IDirectorySystem` that checks for the existence of sub-directories with a matching name.
1 parent f4e68f8 commit bd22c57

File tree

7 files changed

+473
-27
lines changed

7 files changed

+473
-27
lines changed

Source/Testably.Abstractions.FluentAssertions/DirectoryAssertions.cs

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,45 @@ internal DirectoryAssertions(IDirectoryInfo? instance)
1717
}
1818

1919
/// <summary>
20-
/// Asserts that the directory contains exactly one file matching the given <paramref name="searchPattern"/>.
20+
/// Asserts that the current directory has at least <paramref name="minimumCount" /> directories which match the
21+
/// <paramref name="searchPattern" />.
2122
/// </summary>
22-
public AndWhichConstraint<FileSystemAssertions, FileAssertions> HasSingleFileMatching(
23-
string searchPattern = "*", string because = "", params object[] becauseArgs)
23+
public AndConstraint<DirectoryAssertions> HasDirectoriesMatching(
24+
string searchPattern = "*",
25+
int minimumCount = 1,
26+
string because = "",
27+
params object[] becauseArgs)
2428
{
2529
Execute.Assertion
2630
.WithDefaultIdentifier(Identifier)
2731
.BecauseOf(because, becauseArgs)
2832
.ForCondition(Subject != null)
2933
.FailWith(
30-
"You can't assert a directory having a given file if it is null")
34+
"You can't assert a directory having directories if the DirectoryInfo is null.")
3135
.Then
3236
.ForCondition(!string.IsNullOrEmpty(searchPattern))
3337
.FailWith(
34-
"You can't assert a directory having a given file if you don't pass a proper name")
38+
"You can't assert a directory having directories if you don't pass a proper search pattern.")
3539
.Then
3640
.Given(() => Subject!)
3741
.ForCondition(directoryInfo
38-
=> directoryInfo.GetFiles(searchPattern).Length == 1)
42+
=> directoryInfo.GetDirectories(searchPattern).Length >= minimumCount)
3943
.FailWith(
40-
"Expected {context} {1} to contain exactly one file matching {0}{reason}, but found {2}.",
44+
$"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.",
4145
_ => searchPattern,
4246
directoryInfo => directoryInfo.Name,
43-
directoryInfo => directoryInfo.GetFiles(searchPattern).Length);
44-
45-
return new AndWhichConstraint<FileSystemAssertions, FileAssertions>(
46-
new FileSystemAssertions(Subject!.FileSystem),
47-
new FileAssertions(Subject!.GetFiles(searchPattern).Single()));
47+
directoryInfo => directoryInfo.GetDirectories(searchPattern).Length);
48+
49+
return new AndConstraint<DirectoryAssertions>(this);
4850
}
4951

52+
/// <summary>
53+
/// Asserts that the current directory has at least one directory which matches the <paramref name="searchPattern" />.
54+
/// </summary>
55+
public AndConstraint<DirectoryAssertions> HasDirectoryMatching(
56+
string searchPattern = "*", string because = "", params object[] becauseArgs)
57+
=> HasDirectoriesMatching(searchPattern, 1, because, becauseArgs);
58+
5059
/// <summary>
5160
/// Asserts that the current directory has at least one file which matches the <paramref name="searchPattern" />.
5261
/// </summary>
@@ -69,11 +78,11 @@ public AndConstraint<DirectoryAssertions> HasFilesMatching(
6978
.BecauseOf(because, becauseArgs)
7079
.ForCondition(Subject != null)
7180
.FailWith(
72-
"You can't assert a directory having files if the DirectoryInfo is null")
81+
"You can't assert a directory having files if the DirectoryInfo is null.")
7382
.Then
7483
.ForCondition(!string.IsNullOrEmpty(searchPattern))
7584
.FailWith(
76-
"You can't assert a directory having files if you don't pass a proper name")
85+
"You can't assert a directory having files if you don't pass a proper search pattern.")
7786
.Then
7887
.Given(() => Subject!)
7988
.ForCondition(directoryInfo
@@ -86,4 +95,66 @@ public AndConstraint<DirectoryAssertions> HasFilesMatching(
8695

8796
return new AndConstraint<DirectoryAssertions>(this);
8897
}
98+
99+
/// <summary>
100+
/// Asserts that the directory contains exactly one directory matching the given <paramref name="searchPattern" />.
101+
/// </summary>
102+
public AndWhichConstraint<FileSystemAssertions, DirectoryAssertions> HasSingleDirectoryMatching(
103+
string searchPattern = "*", string because = "", params object[] becauseArgs)
104+
{
105+
Execute.Assertion
106+
.WithDefaultIdentifier(Identifier)
107+
.BecauseOf(because, becauseArgs)
108+
.ForCondition(Subject != null)
109+
.FailWith(
110+
"You can't assert a directory having a given directory if it is null.")
111+
.Then
112+
.ForCondition(!string.IsNullOrEmpty(searchPattern))
113+
.FailWith(
114+
"You can't assert a directory having a given directory if you don't pass a proper search pattern.")
115+
.Then
116+
.Given(() => Subject!)
117+
.ForCondition(directoryInfo
118+
=> directoryInfo.GetDirectories(searchPattern).Length == 1)
119+
.FailWith(
120+
"Expected {context} {1} to contain exactly one directory matching {0}{reason}, but found {2}.",
121+
_ => searchPattern,
122+
directoryInfo => directoryInfo.Name,
123+
directoryInfo => directoryInfo.GetDirectories(searchPattern).Length);
124+
125+
return new AndWhichConstraint<FileSystemAssertions, DirectoryAssertions>(
126+
new FileSystemAssertions(Subject!.FileSystem),
127+
new DirectoryAssertions(Subject!.GetDirectories(searchPattern).Single()));
128+
}
129+
130+
/// <summary>
131+
/// Asserts that the directory contains exactly one file matching the given <paramref name="searchPattern" />.
132+
/// </summary>
133+
public AndWhichConstraint<FileSystemAssertions, FileAssertions> HasSingleFileMatching(
134+
string searchPattern = "*", string because = "", params object[] becauseArgs)
135+
{
136+
Execute.Assertion
137+
.WithDefaultIdentifier(Identifier)
138+
.BecauseOf(because, becauseArgs)
139+
.ForCondition(Subject != null)
140+
.FailWith(
141+
"You can't assert a directory having a given file if it is null.")
142+
.Then
143+
.ForCondition(!string.IsNullOrEmpty(searchPattern))
144+
.FailWith(
145+
"You can't assert a directory having a given file if you don't pass a proper search pattern.")
146+
.Then
147+
.Given(() => Subject!)
148+
.ForCondition(directoryInfo
149+
=> directoryInfo.GetFiles(searchPattern).Length == 1)
150+
.FailWith(
151+
"Expected {context} {1} to contain exactly one file matching {0}{reason}, but found {2}.",
152+
_ => searchPattern,
153+
directoryInfo => directoryInfo.Name,
154+
directoryInfo => directoryInfo.GetFiles(searchPattern).Length);
155+
156+
return new AndWhichConstraint<FileSystemAssertions, FileAssertions>(
157+
new FileSystemAssertions(Subject!.FileSystem),
158+
new FileAssertions(Subject!.GetFiles(searchPattern).Single()));
159+
}
89160
}

Source/Testably.Abstractions.FluentAssertions/DirectoryInfoAssertions.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ internal DirectoryInfoAssertions(IDirectoryInfo? instance)
1414
{
1515
}
1616

17+
/// <summary>
18+
/// Asserts that the current directory has at least one directory which matches the <paramref name="searchPattern" />.
19+
/// </summary>
20+
public AndConstraint<DirectoryInfoAssertions> HaveDirectoryMatching(
21+
string searchPattern = "*", string because = "", params object[] becauseArgs)
22+
{
23+
new DirectoryAssertions(Subject).HasDirectoryMatching(searchPattern, because, becauseArgs);
24+
return new AndConstraint<DirectoryInfoAssertions>(this);
25+
}
26+
1727
/// <summary>
1828
/// Asserts that the current directory has at least one file which matches the <paramref name="searchPattern" />.
1929
/// </summary>
@@ -24,12 +34,23 @@ public AndConstraint<DirectoryInfoAssertions> HaveFileMatching(
2434
return new AndConstraint<DirectoryInfoAssertions>(this);
2535
}
2636

37+
/// <summary>
38+
/// Asserts that the directory contains exactly one directory matching the given <paramref name="searchPattern" />.
39+
/// </summary>
40+
public AndWhichConstraint<FileSystemAssertions, DirectoryAssertions> HaveSingleDirectory(
41+
string searchPattern = "*", string because = "", params object[] becauseArgs)
42+
{
43+
return new DirectoryAssertions(Subject).HasSingleDirectoryMatching(searchPattern, because,
44+
becauseArgs);
45+
}
46+
2747
/// <summary>
2848
/// Asserts that the directory contains exactly one file matching the given <paramref name="searchPattern" />.
2949
/// </summary>
3050
public AndWhichConstraint<FileSystemAssertions, FileAssertions> HaveSingleFile(
3151
string searchPattern = "*", string because = "", params object[] becauseArgs)
3252
{
33-
return new DirectoryAssertions(Subject).HasSingleFileMatching(searchPattern, because, becauseArgs);
53+
return new DirectoryAssertions(Subject).HasSingleFileMatching(searchPattern, because,
54+
becauseArgs);
3455
}
3556
}

Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public AndConstraint<FileAssertions> DoesNotHaveAttribute(
2929
.BecauseOf(because, becauseArgs)
3030
.ForCondition(Subject != null)
3131
.FailWith(
32-
$"You can't assert that the file does not have attribute {attribute} if it is null")
32+
$"You can't assert that the file does not have attribute {attribute} if it is null.")
3333
.Then
3434
.Given(() => Subject!)
3535
.ForCondition(fileInfo => !fileInfo.Attributes.HasFlag(attribute))
@@ -51,7 +51,7 @@ public AndConstraint<FileAssertions> HasAttribute(
5151
.BecauseOf(because, becauseArgs)
5252
.ForCondition(Subject != null)
5353
.FailWith(
54-
$"You can't assert that the file has attribute {attribute} if it is null")
54+
$"You can't assert that the file has attribute {attribute} if it is null.")
5555
.Then
5656
.Given(() => Subject!)
5757
.ForCondition(fileInfo => fileInfo.Attributes.HasFlag(attribute))
@@ -73,7 +73,7 @@ public AndConstraint<FileAssertions> HasContent(
7373
.BecauseOf(because, becauseArgs)
7474
.ForCondition(Subject != null)
7575
.FailWith(
76-
"You can't assert the content of a file if the FileInfo is null")
76+
"You can't assert the content of a file if the FileInfo is null.")
7777
.Then
7878
.Given(() => Subject!)
7979
.ForCondition(fileInfo => fileInfo.FileSystem.File
@@ -97,7 +97,7 @@ public AndConstraint<FileAssertions> HasContent(
9797
.BecauseOf(because, becauseArgs)
9898
.ForCondition(Subject != null)
9999
.FailWith(
100-
"You can't assert the content of a file if the FileInfo is null")
100+
"You can't assert the content of a file if the FileInfo is null.")
101101
.Then
102102
.Given(() => Subject!)
103103
.ForCondition(fileInfo => pattern.Matches(
@@ -121,7 +121,7 @@ public AndConstraint<FileAssertions> HasContent(
121121
.BecauseOf(because, becauseArgs)
122122
.ForCondition(Subject != null)
123123
.FailWith(
124-
"You can't assert the content of a file if the FileInfo is null")
124+
"You can't assert the content of a file if the FileInfo is null.")
125125
.Then
126126
.Given(() => Subject!)
127127
.ForCondition(fileInfo => pattern.Matches(
@@ -144,7 +144,7 @@ public AndConstraint<FileAssertions> IsNotReadOnly(
144144
.BecauseOf(because, becauseArgs)
145145
.ForCondition(Subject != null)
146146
.FailWith(
147-
"You can't assert that the file is not read-only if it is null")
147+
"You can't assert that the file is not read-only if it is null.")
148148
.Then
149149
.Given(() => Subject!)
150150
.ForCondition(fileInfo => !fileInfo.IsReadOnly)
@@ -166,7 +166,7 @@ public AndConstraint<FileAssertions> IsReadOnly(
166166
.BecauseOf(because, becauseArgs)
167167
.ForCondition(Subject != null)
168168
.FailWith(
169-
"You can't assert that the file is read-only if it is null")
169+
"You can't assert that the file is read-only if it is null.")
170170
.Then
171171
.Given(() => Subject!)
172172
.ForCondition(fileInfo => fileInfo.IsReadOnly)

Source/Testably.Abstractions.FluentAssertions/FileSystemAssertions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public AndWhichConstraint<FileSystemAssertions, DirectoryAssertions> HaveDirecto
2424
.WithDefaultIdentifier(Identifier)
2525
.BecauseOf(because, becauseArgs)
2626
.ForCondition(!string.IsNullOrEmpty(path))
27-
.FailWith("You can't assert that a directory exists if you don't pass a proper name.")
27+
.FailWith("You can't assert that a directory exists if you don't pass a proper path.")
2828
.Then
2929
.Given(() => Subject.DirectoryInfo.New(path))
3030
.ForCondition(directoryInfo => directoryInfo.Exists)
@@ -46,7 +46,7 @@ public AndWhichConstraint<FileSystemAssertions, FileAssertions> HaveFile(
4646
.WithDefaultIdentifier(Identifier)
4747
.BecauseOf(because, becauseArgs)
4848
.ForCondition(!string.IsNullOrEmpty(path))
49-
.FailWith("You can't assert that a file exists if you don't pass a proper name.")
49+
.FailWith("You can't assert that a file exists if you don't pass a proper path.")
5050
.Then
5151
.Given(() => Subject.FileInfo.New(path))
5252
.ForCondition(fileInfo => fileInfo.Exists)
@@ -69,7 +69,7 @@ public AndWhichConstraint<FileSystemAssertions, DirectoryAssertions> NotHaveDire
6969
.BecauseOf(because, becauseArgs)
7070
.ForCondition(!string.IsNullOrEmpty(path))
7171
.FailWith(
72-
"You can't assert that a directory does not exist if you don't pass a proper name.")
72+
"You can't assert that a directory does not exist if you don't pass a proper path.")
7373
.Then
7474
.Given(() => Subject.DirectoryInfo.New(path))
7575
.ForCondition(directoryInfo => !directoryInfo.Exists)
@@ -92,7 +92,7 @@ public AndWhichConstraint<FileSystemAssertions, FileAssertions> NotHaveFile(
9292
.BecauseOf(because, becauseArgs)
9393
.ForCondition(!string.IsNullOrEmpty(path))
9494
.FailWith(
95-
"You can't assert that a file does not exist if you don't pass a proper name.")
95+
"You can't assert that a file does not exist if you don't pass a proper path.")
9696
.Then
9797
.Given(() => Subject.FileInfo.New(path))
9898
.ForCondition(fileInfo => !fileInfo.Exists)

Source/Testably.Abstractions.FluentAssertions/FileSystemInfoAssertions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public AndConstraint<TFileSystemInfo> Exist(
2626
.WithDefaultIdentifier(Identifier)
2727
.BecauseOf(because, becauseArgs)
2828
.ForCondition(Subject != null)
29-
.FailWith("You can't assert that the {context} exists if it is null")
29+
.FailWith("You can't assert that the {context} exists if it is null.")
3030
.Then
3131
.Given(() => Subject!)
3232
.ForCondition(fileSystemInfo => fileSystemInfo.Exists)

0 commit comments

Comments
 (0)