Skip to content

Commit f196f11

Browse files
vbreussvbtig
andauthored
feat: add assertion for HasAttribute and DoesNotHaveAttribute for files (#33)
Add assertions for attributes on files. Co-authored-by: Valentin Breuß <[email protected]>
1 parent 6a04680 commit f196f11

File tree

4 files changed

+248
-3
lines changed

4 files changed

+248
-3
lines changed

Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Linq;
1+
using System.IO;
2+
using System.Linq;
23
using System.Text;
34

45
namespace Testably.Abstractions.FluentAssertions;
@@ -17,6 +18,50 @@ internal FileAssertions(IFileInfo? instance)
1718
{
1819
}
1920

21+
/// <summary>
22+
/// Asserts that the current file does not have the given <paramref name="attribute" />.
23+
/// </summary>
24+
public AndConstraint<FileAssertions> DoesNotHaveAttribute(
25+
FileAttributes attribute, string because = "", params object[] becauseArgs)
26+
{
27+
Execute.Assertion
28+
.WithDefaultIdentifier(Identifier)
29+
.BecauseOf(because, becauseArgs)
30+
.ForCondition(Subject != null)
31+
.FailWith(
32+
$"You can't assert that the file does not have attribute {attribute} if it is null")
33+
.Then
34+
.Given(() => Subject!)
35+
.ForCondition(fileInfo => !fileInfo.Attributes.HasFlag(attribute))
36+
.FailWith(
37+
$"Expected {{context}} {{0}} not to have attribute {attribute}{{reason}}, but it did.",
38+
fileInfo => fileInfo.Name);
39+
40+
return new AndConstraint<FileAssertions>(this);
41+
}
42+
43+
/// <summary>
44+
/// Asserts that the current file has the given <paramref name="attribute" />.
45+
/// </summary>
46+
public AndConstraint<FileAssertions> HasAttribute(
47+
FileAttributes attribute, string because = "", params object[] becauseArgs)
48+
{
49+
Execute.Assertion
50+
.WithDefaultIdentifier(Identifier)
51+
.BecauseOf(because, becauseArgs)
52+
.ForCondition(Subject != null)
53+
.FailWith(
54+
$"You can't assert that the file has attribute {attribute} if it is null")
55+
.Then
56+
.Given(() => Subject!)
57+
.ForCondition(fileInfo => fileInfo.Attributes.HasFlag(attribute))
58+
.FailWith(
59+
$"Expected {{context}} {{0}} to have attribute {attribute}{{reason}}, but it did not.",
60+
fileInfo => fileInfo.Name);
61+
62+
return new AndConstraint<FileAssertions>(this);
63+
}
64+
2065
/// <summary>
2166
/// Asserts that the binary content of the current file is equivalent to the given <paramref name="bytes" />.
2267
/// </summary>
@@ -99,7 +144,7 @@ public AndConstraint<FileAssertions> IsNotReadOnly(
99144
.BecauseOf(because, becauseArgs)
100145
.ForCondition(Subject != null)
101146
.FailWith(
102-
"You can't assert that the file is not read-only if the FileInfo is null")
147+
"You can't assert that the file is not read-only if it is null")
103148
.Then
104149
.Given(() => Subject!)
105150
.ForCondition(fileInfo => !fileInfo.IsReadOnly)
@@ -121,7 +166,7 @@ public AndConstraint<FileAssertions> IsReadOnly(
121166
.BecauseOf(because, becauseArgs)
122167
.ForCondition(Subject != null)
123168
.FailWith(
124-
"You can't assert that the file is read-only if the FileInfo is null")
169+
"You can't assert that the file is read-only if it is null")
125170
.Then
126171
.Given(() => Subject!)
127172
.ForCondition(fileInfo => fileInfo.IsReadOnly)

Source/Testably.Abstractions.FluentAssertions/FileInfoAssertions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.IO;
12
using System.Text;
23

34
namespace Testably.Abstractions.FluentAssertions;
@@ -26,6 +27,16 @@ public AndConstraint<FileInfoAssertions> BeReadOnly(
2627
return new AndConstraint<FileInfoAssertions>(this);
2728
}
2829

30+
/// <summary>
31+
/// Asserts that the current file has the given <paramref name="attribute" />.
32+
/// </summary>
33+
public AndConstraint<FileInfoAssertions> HaveAttribute(
34+
FileAttributes attribute, string because = "", params object[] becauseArgs)
35+
{
36+
new FileAssertions(Subject).HasAttribute(attribute, because, becauseArgs);
37+
return new AndConstraint<FileInfoAssertions>(this);
38+
}
39+
2940
/// <summary>
3041
/// Asserts that the binary content of the current file is equivalent to the given <paramref name="bytes" />.
3142
/// </summary>
@@ -66,4 +77,14 @@ public AndConstraint<FileInfoAssertions> NotBeReadOnly(
6677
new FileAssertions(Subject).IsNotReadOnly(because, becauseArgs);
6778
return new AndConstraint<FileInfoAssertions>(this);
6879
}
80+
81+
/// <summary>
82+
/// Asserts that the current file does not have the given <paramref name="attribute" />.
83+
/// </summary>
84+
public AndConstraint<FileInfoAssertions> NotHaveAttribute(
85+
FileAttributes attribute, string because = "", params object[] becauseArgs)
86+
{
87+
new FileAssertions(Subject).DoesNotHaveAttribute(attribute, because, becauseArgs);
88+
return new AndConstraint<FileInfoAssertions>(this);
89+
}
6990
}

Tests/Testably.Abstractions.FluentAssertions.Tests/FileAssertionsTests.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using AutoFixture.Xunit2;
22
using FluentAssertions;
33
using System;
4+
using System.IO;
45
using System.Linq;
56
using System.Text;
67
using Testably.Abstractions.Testing;
@@ -11,6 +12,79 @@ namespace Testably.Abstractions.FluentAssertions.Tests;
1112

1213
public class FileAssertionsTests
1314
{
15+
[Theory]
16+
[AutoData]
17+
public void DoesNotHaveAttribute_WithAttribute_ShouldThrow(
18+
FileDescription fileDescription,
19+
string because)
20+
{
21+
fileDescription.IsReadOnly = true;
22+
MockFileSystem fileSystem = new();
23+
fileSystem.Initialize()
24+
.With(fileDescription);
25+
FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
26+
27+
Exception? exception = Record.Exception(() =>
28+
{
29+
sut.DoesNotHaveAttribute(FileAttributes.ReadOnly, because);
30+
});
31+
32+
exception.Should().NotBeNull();
33+
exception!.Message.Should()
34+
.Be(
35+
$"Expected file \"{fileDescription.Name}\" not to have attribute {FileAttributes.ReadOnly} {because}, but it did.");
36+
}
37+
38+
[Theory]
39+
[AutoData]
40+
public void DoesNotHaveAttribute_WithoutAttribute_ShouldNotThrow(
41+
FileDescription fileDescription)
42+
{
43+
fileDescription.IsReadOnly = false;
44+
MockFileSystem fileSystem = new();
45+
fileSystem.Initialize()
46+
.With(fileDescription);
47+
FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
48+
49+
sut.DoesNotHaveAttribute(FileAttributes.ReadOnly);
50+
}
51+
52+
[Theory]
53+
[AutoData]
54+
public void HasAttribute_WithAttribute_ShouldNotThrow(FileDescription fileDescription)
55+
{
56+
fileDescription.IsReadOnly = true;
57+
MockFileSystem fileSystem = new();
58+
fileSystem.Initialize()
59+
.With(fileDescription);
60+
FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
61+
62+
sut.HasAttribute(FileAttributes.ReadOnly);
63+
}
64+
65+
[Theory]
66+
[AutoData]
67+
public void HasAttribute_WithoutAttribute_ShouldThrow(
68+
FileDescription fileDescription,
69+
string because)
70+
{
71+
fileDescription.IsReadOnly = false;
72+
MockFileSystem fileSystem = new();
73+
fileSystem.Initialize()
74+
.With(fileDescription);
75+
FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
76+
77+
Exception? exception = Record.Exception(() =>
78+
{
79+
sut.HasAttribute(FileAttributes.ReadOnly, because);
80+
});
81+
82+
exception.Should().NotBeNull();
83+
exception!.Message.Should()
84+
.Be(
85+
$"Expected file \"{fileDescription.Name}\" to have attribute {FileAttributes.ReadOnly} {because}, but it did not.");
86+
}
87+
1488
[Theory]
1589
[AutoData]
1690
public void HasContent_Bytes_FullContent_ShouldNotThrow(

Tests/Testably.Abstractions.FluentAssertions.Tests/FileInfoAssertionsTests.cs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using AutoFixture.Xunit2;
22
using FluentAssertions;
33
using System;
4+
using System.IO;
45
using System.IO.Abstractions;
56
using System.Linq;
67
using System.Text;
@@ -64,6 +65,58 @@ public void BeReadOnly_WithWritableFile_ShouldThrow(
6465
$"Expected file \"{fileDescription.Name}\" to be read-only {because}, but it was not.");
6566
}
6667

68+
[Theory]
69+
[AutoData]
70+
public void HaveAttribute_Null_ShouldThrow(string because)
71+
{
72+
IFileInfo? sut = null;
73+
74+
Exception? exception = Record.Exception(() =>
75+
{
76+
sut.Should().HaveAttribute(FileAttributes.ReadOnly, because);
77+
});
78+
79+
exception.Should().NotBeNull();
80+
exception!.Message.Should().Contain("null");
81+
exception.Message.Should().NotContain(because);
82+
}
83+
84+
[Theory]
85+
[AutoData]
86+
public void HaveAttribute_WithAttribute_ShouldNotThrow(FileDescription fileDescription)
87+
{
88+
fileDescription.IsReadOnly = true;
89+
MockFileSystem fileSystem = new();
90+
fileSystem.Initialize()
91+
.With(fileDescription);
92+
IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
93+
94+
sut.Should().HaveAttribute(FileAttributes.ReadOnly);
95+
}
96+
97+
[Theory]
98+
[AutoData]
99+
public void HaveAttribute_WithoutAttribute_ShouldThrow(
100+
FileDescription fileDescription,
101+
string because)
102+
{
103+
fileDescription.IsReadOnly = false;
104+
MockFileSystem fileSystem = new();
105+
fileSystem.Initialize()
106+
.With(fileDescription);
107+
IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
108+
109+
Exception? exception = Record.Exception(() =>
110+
{
111+
sut.Should().HaveAttribute(FileAttributes.ReadOnly, because);
112+
});
113+
114+
exception.Should().NotBeNull();
115+
exception!.Message.Should()
116+
.Be(
117+
$"Expected file \"{fileDescription.Name}\" to have attribute {FileAttributes.ReadOnly} {because}, but it did not.");
118+
}
119+
67120
[Theory]
68121
[AutoData]
69122
public void HaveContent_Bytes_FullContent_ShouldNotThrow(
@@ -320,4 +373,56 @@ public void NotBeReadOnly_WithWritableFile_ShouldNotThrow(FileDescription fileDe
320373

321374
sut.Should().NotBeReadOnly();
322375
}
376+
377+
[Theory]
378+
[AutoData]
379+
public void NotHaveAttribute_Null_ShouldThrow(string because)
380+
{
381+
IFileInfo? sut = null;
382+
383+
Exception? exception = Record.Exception(() =>
384+
{
385+
sut.Should().NotHaveAttribute(FileAttributes.ReadOnly, because);
386+
});
387+
388+
exception.Should().NotBeNull();
389+
exception!.Message.Should().Contain("null");
390+
exception.Message.Should().NotContain(because);
391+
}
392+
393+
[Theory]
394+
[AutoData]
395+
public void NotHaveAttribute_WithAttribute_ShouldThrow(
396+
FileDescription fileDescription,
397+
string because)
398+
{
399+
fileDescription.IsReadOnly = true;
400+
MockFileSystem fileSystem = new();
401+
fileSystem.Initialize()
402+
.With(fileDescription);
403+
IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
404+
405+
Exception? exception = Record.Exception(() =>
406+
{
407+
sut.Should().NotHaveAttribute(FileAttributes.ReadOnly, because);
408+
});
409+
410+
exception.Should().NotBeNull();
411+
exception!.Message.Should()
412+
.Be(
413+
$"Expected file \"{fileDescription.Name}\" not to have attribute {FileAttributes.ReadOnly} {because}, but it did.");
414+
}
415+
416+
[Theory]
417+
[AutoData]
418+
public void NotHaveAttribute_WithoutAttribute_ShouldNotThrow(FileDescription fileDescription)
419+
{
420+
fileDescription.IsReadOnly = false;
421+
MockFileSystem fileSystem = new();
422+
fileSystem.Initialize()
423+
.With(fileDescription);
424+
IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
425+
426+
sut.Should().NotHaveAttribute(FileAttributes.ReadOnly);
427+
}
323428
}

0 commit comments

Comments
 (0)