diff --git a/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs b/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs
index 0ea1d98..f898883 100644
--- a/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs
+++ b/Source/Testably.Abstractions.FluentAssertions/FileAssertions.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System.IO;
+using System.Linq;
using System.Text;
namespace Testably.Abstractions.FluentAssertions;
@@ -17,6 +18,50 @@ internal FileAssertions(IFileInfo? instance)
{
}
+ ///
+ /// Asserts that the current file does not have the given .
+ ///
+ public AndConstraint DoesNotHaveAttribute(
+ FileAttributes attribute, string because = "", params object[] becauseArgs)
+ {
+ Execute.Assertion
+ .WithDefaultIdentifier(Identifier)
+ .BecauseOf(because, becauseArgs)
+ .ForCondition(Subject != null)
+ .FailWith(
+ $"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))
+ .FailWith(
+ $"Expected {{context}} {{0}} not to have attribute {attribute}{{reason}}, but it did.",
+ fileInfo => fileInfo.Name);
+
+ return new AndConstraint(this);
+ }
+
+ ///
+ /// Asserts that the current file has the given .
+ ///
+ public AndConstraint HasAttribute(
+ FileAttributes attribute, string because = "", params object[] becauseArgs)
+ {
+ Execute.Assertion
+ .WithDefaultIdentifier(Identifier)
+ .BecauseOf(because, becauseArgs)
+ .ForCondition(Subject != null)
+ .FailWith(
+ $"You can't assert that the file has attribute {attribute} if it is null")
+ .Then
+ .Given(() => Subject!)
+ .ForCondition(fileInfo => fileInfo.Attributes.HasFlag(attribute))
+ .FailWith(
+ $"Expected {{context}} {{0}} to have attribute {attribute}{{reason}}, but it did not.",
+ fileInfo => fileInfo.Name);
+
+ return new AndConstraint(this);
+ }
+
///
/// Asserts that the binary content of the current file is equivalent to the given .
///
@@ -99,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 the FileInfo is null")
+ "You can't assert that the file is not read-only if it is null")
.Then
.Given(() => Subject!)
.ForCondition(fileInfo => !fileInfo.IsReadOnly)
@@ -121,7 +166,7 @@ public AndConstraint IsReadOnly(
.BecauseOf(because, becauseArgs)
.ForCondition(Subject != null)
.FailWith(
- "You can't assert that the file is read-only if the FileInfo 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/FileInfoAssertions.cs b/Source/Testably.Abstractions.FluentAssertions/FileInfoAssertions.cs
index 61dd121..f0ead05 100644
--- a/Source/Testably.Abstractions.FluentAssertions/FileInfoAssertions.cs
+++ b/Source/Testably.Abstractions.FluentAssertions/FileInfoAssertions.cs
@@ -1,3 +1,4 @@
+using System.IO;
using System.Text;
namespace Testably.Abstractions.FluentAssertions;
@@ -26,6 +27,16 @@ public AndConstraint BeReadOnly(
return new AndConstraint(this);
}
+ ///
+ /// Asserts that the current file has the given .
+ ///
+ public AndConstraint HaveAttribute(
+ FileAttributes attribute, string because = "", params object[] becauseArgs)
+ {
+ new FileAssertions(Subject).HasAttribute(attribute, because, becauseArgs);
+ return new AndConstraint(this);
+ }
+
///
/// Asserts that the binary content of the current file is equivalent to the given .
///
@@ -66,4 +77,14 @@ public AndConstraint NotBeReadOnly(
new FileAssertions(Subject).IsNotReadOnly(because, becauseArgs);
return new AndConstraint(this);
}
+
+ ///
+ /// Asserts that the current file does not have the given .
+ ///
+ public AndConstraint NotHaveAttribute(
+ FileAttributes attribute, string because = "", params object[] becauseArgs)
+ {
+ new FileAssertions(Subject).DoesNotHaveAttribute(attribute, because, becauseArgs);
+ return new AndConstraint(this);
+ }
}
diff --git a/Tests/Testably.Abstractions.FluentAssertions.Tests/FileAssertionsTests.cs b/Tests/Testably.Abstractions.FluentAssertions.Tests/FileAssertionsTests.cs
index 52171f2..d505b37 100644
--- a/Tests/Testably.Abstractions.FluentAssertions.Tests/FileAssertionsTests.cs
+++ b/Tests/Testably.Abstractions.FluentAssertions.Tests/FileAssertionsTests.cs
@@ -1,6 +1,7 @@
using AutoFixture.Xunit2;
using FluentAssertions;
using System;
+using System.IO;
using System.Linq;
using System.Text;
using Testably.Abstractions.Testing;
@@ -11,6 +12,79 @@ namespace Testably.Abstractions.FluentAssertions.Tests;
public class FileAssertionsTests
{
+ [Theory]
+ [AutoData]
+ public void DoesNotHaveAttribute_WithAttribute_ShouldThrow(
+ FileDescription fileDescription,
+ string because)
+ {
+ fileDescription.IsReadOnly = true;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.DoesNotHaveAttribute(FileAttributes.ReadOnly, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected file \"{fileDescription.Name}\" not to have attribute {FileAttributes.ReadOnly} {because}, but it did.");
+ }
+
+ [Theory]
+ [AutoData]
+ public void DoesNotHaveAttribute_WithoutAttribute_ShouldNotThrow(
+ FileDescription fileDescription)
+ {
+ fileDescription.IsReadOnly = false;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
+
+ sut.DoesNotHaveAttribute(FileAttributes.ReadOnly);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HasAttribute_WithAttribute_ShouldNotThrow(FileDescription fileDescription)
+ {
+ fileDescription.IsReadOnly = true;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
+
+ sut.HasAttribute(FileAttributes.ReadOnly);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HasAttribute_WithoutAttribute_ShouldThrow(
+ FileDescription fileDescription,
+ string because)
+ {
+ fileDescription.IsReadOnly = false;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ FileAssertions? sut = fileSystem.Should().HaveFile(fileDescription.Name).Which;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.HasAttribute(FileAttributes.ReadOnly, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected file \"{fileDescription.Name}\" to have attribute {FileAttributes.ReadOnly} {because}, but it did not.");
+ }
+
[Theory]
[AutoData]
public void HasContent_Bytes_FullContent_ShouldNotThrow(
diff --git a/Tests/Testably.Abstractions.FluentAssertions.Tests/FileInfoAssertionsTests.cs b/Tests/Testably.Abstractions.FluentAssertions.Tests/FileInfoAssertionsTests.cs
index a9ccf24..4989ca1 100644
--- a/Tests/Testably.Abstractions.FluentAssertions.Tests/FileInfoAssertionsTests.cs
+++ b/Tests/Testably.Abstractions.FluentAssertions.Tests/FileInfoAssertionsTests.cs
@@ -1,6 +1,7 @@
using AutoFixture.Xunit2;
using FluentAssertions;
using System;
+using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text;
@@ -64,6 +65,58 @@ public void BeReadOnly_WithWritableFile_ShouldThrow(
$"Expected file \"{fileDescription.Name}\" to be read-only {because}, but it was not.");
}
+ [Theory]
+ [AutoData]
+ public void HaveAttribute_Null_ShouldThrow(string because)
+ {
+ IFileInfo? sut = null;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveAttribute(FileAttributes.ReadOnly, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().Contain("null");
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveAttribute_WithAttribute_ShouldNotThrow(FileDescription fileDescription)
+ {
+ fileDescription.IsReadOnly = true;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
+
+ sut.Should().HaveAttribute(FileAttributes.ReadOnly);
+ }
+
+ [Theory]
+ [AutoData]
+ public void HaveAttribute_WithoutAttribute_ShouldThrow(
+ FileDescription fileDescription,
+ string because)
+ {
+ fileDescription.IsReadOnly = false;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().HaveAttribute(FileAttributes.ReadOnly, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected file \"{fileDescription.Name}\" to have attribute {FileAttributes.ReadOnly} {because}, but it did not.");
+ }
+
[Theory]
[AutoData]
public void HaveContent_Bytes_FullContent_ShouldNotThrow(
@@ -320,4 +373,56 @@ public void NotBeReadOnly_WithWritableFile_ShouldNotThrow(FileDescription fileDe
sut.Should().NotBeReadOnly();
}
+
+ [Theory]
+ [AutoData]
+ public void NotHaveAttribute_Null_ShouldThrow(string because)
+ {
+ IFileInfo? sut = null;
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().NotHaveAttribute(FileAttributes.ReadOnly, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should().Contain("null");
+ exception.Message.Should().NotContain(because);
+ }
+
+ [Theory]
+ [AutoData]
+ public void NotHaveAttribute_WithAttribute_ShouldThrow(
+ FileDescription fileDescription,
+ string because)
+ {
+ fileDescription.IsReadOnly = true;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
+
+ Exception? exception = Record.Exception(() =>
+ {
+ sut.Should().NotHaveAttribute(FileAttributes.ReadOnly, because);
+ });
+
+ exception.Should().NotBeNull();
+ exception!.Message.Should()
+ .Be(
+ $"Expected file \"{fileDescription.Name}\" not to have attribute {FileAttributes.ReadOnly} {because}, but it did.");
+ }
+
+ [Theory]
+ [AutoData]
+ public void NotHaveAttribute_WithoutAttribute_ShouldNotThrow(FileDescription fileDescription)
+ {
+ fileDescription.IsReadOnly = false;
+ MockFileSystem fileSystem = new();
+ fileSystem.Initialize()
+ .With(fileDescription);
+ IFileInfo sut = fileSystem.FileInfo.New(fileDescription.Name);
+
+ sut.Should().NotHaveAttribute(FileAttributes.ReadOnly);
+ }
}