From 192f48ca8d0941e3108a0b7506393856c974afef Mon Sep 17 00:00:00 2001 From: IT-VBFK <49762557+IT-VBFK@users.noreply.github.com> Date: Fri, 15 Apr 2022 10:20:02 +0200 Subject: [PATCH] Add `BeDefined` and `NotBeDefined` to `EnumAssertions` (#1888) Add methods `BeDefined` and `NotBeDefined` to `EnumAssertions` --- .../Primitives/EnumAssertions.cs | 52 ++++++++++++ .../FluentAssertions/net47.verified.txt | 2 + .../FluentAssertions/net6.0.verified.txt | 2 + .../netcoreapp2.1.verified.txt | 2 + .../netcoreapp3.0.verified.txt | 2 + .../netstandard2.0.verified.txt | 2 + .../netstandard2.1.verified.txt | 2 + .../Primitives/EnumAssertionSpecs.cs | 79 +++++++++++++++++++ docs/_pages/enums.md | 8 ++ docs/_pages/releases.md | 5 ++ 10 files changed, 156 insertions(+) diff --git a/Src/FluentAssertions/Primitives/EnumAssertions.cs b/Src/FluentAssertions/Primitives/EnumAssertions.cs index 77a6ee052e..c6974a806b 100644 --- a/Src/FluentAssertions/Primitives/EnumAssertions.cs +++ b/Src/FluentAssertions/Primitives/EnumAssertions.cs @@ -129,6 +129,58 @@ public AndConstraint NotBe(TEnum? unexpected, string because = "", return new AndConstraint((TAssertions)this); } + /// + /// Asserts that the current value of is defined inside the enum. + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public AndConstraint BeDefined(string because = "", params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .WithExpectation("Expected {context:the enum} to be defined in {0}{reason}, ", typeof(TEnum)) + .ForCondition(Subject is not null) + .FailWith("but found .") + .Then + .ForCondition(Enum.IsDefined(typeof(TEnum), Subject)) + .FailWith("but it is not.") + .Then + .ClearExpectation(); + + return new AndConstraint((TAssertions)this); + } + + /// + /// Asserts that the current value of is not defined inside the enum. + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public AndConstraint NotBeDefined(string because = "", params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .WithExpectation("Did not expect {context:the enum} to be defined in {0}{reason}, ", typeof(TEnum)) + .ForCondition(Subject is not null) + .FailWith("but found .") + .Then + .ForCondition(!Enum.IsDefined(typeof(TEnum), Subject)) + .FailWith("but it is.") + .Then + .ClearExpectation(); + + return new AndConstraint((TAssertions)this); + } + /// /// Asserts that the current is exactly equal to the value. /// diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt index 6ff5858bab..4682ecdc00 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt @@ -1887,6 +1887,7 @@ namespace FluentAssertions.Primitives public TEnum? Subject { get; } public FluentAssertions.AndConstraint Be(TEnum expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint BeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public override bool Equals(object obj) { } @@ -1899,6 +1900,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum? unexpected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveFlag(TEnum unexpectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveSameNameAs(T unexpected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt index cf6defd2c8..9fa5350cd3 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt @@ -1944,6 +1944,7 @@ namespace FluentAssertions.Primitives public TEnum? Subject { get; } public FluentAssertions.AndConstraint Be(TEnum expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint BeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public override bool Equals(object obj) { } @@ -1956,6 +1957,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum? unexpected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveFlag(TEnum unexpectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveSameNameAs(T unexpected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt index 08f866a950..16751afb56 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt @@ -1887,6 +1887,7 @@ namespace FluentAssertions.Primitives public TEnum? Subject { get; } public FluentAssertions.AndConstraint Be(TEnum expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint BeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public override bool Equals(object obj) { } @@ -1899,6 +1900,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum? unexpected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveFlag(TEnum unexpectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveSameNameAs(T unexpected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt index fe3a364b04..f9e4753c6e 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt @@ -1887,6 +1887,7 @@ namespace FluentAssertions.Primitives public TEnum? Subject { get; } public FluentAssertions.AndConstraint Be(TEnum expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint BeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public override bool Equals(object obj) { } @@ -1899,6 +1900,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum? unexpected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveFlag(TEnum unexpectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveSameNameAs(T unexpected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt index e210dc45ac..ec7b7c008f 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt @@ -1839,6 +1839,7 @@ namespace FluentAssertions.Primitives public TEnum? Subject { get; } public FluentAssertions.AndConstraint Be(TEnum expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint BeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public override bool Equals(object obj) { } @@ -1851,6 +1852,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum? unexpected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveFlag(TEnum unexpectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveSameNameAs(T unexpected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt index e0c14517ca..25938a8a06 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt @@ -1887,6 +1887,7 @@ namespace FluentAssertions.Primitives public TEnum? Subject { get; } public FluentAssertions.AndConstraint Be(TEnum expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint BeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public override bool Equals(object obj) { } @@ -1899,6 +1900,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(TEnum? unexpected, string because = "", params object[] becauseArgs) { } + public FluentAssertions.AndConstraint NotBeDefined(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveFlag(TEnum unexpectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotHaveSameNameAs(T unexpected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } diff --git a/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs index 2ffaff3042..b38e6008d1 100644 --- a/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs @@ -791,5 +791,84 @@ public void An_enum_cannot_be_part_of_a_null_list() } #endregion + + #region Be defined / Not be defined + + [Fact] + public void A_valid_entry_of_an_enum_is_defined() + { + // Arrange + var dayOfWeek = (DayOfWeek)1; + + // Act / Assert + dayOfWeek.Should().BeDefined(); + } + + [Fact] + public void If_a_value_casted_to_an_enum_type_and_it_does_not_exist_in_the_enum_it_throws() + { + // Arrange + var dayOfWeek = (DayOfWeek)999; + + // Act + Action act = () => dayOfWeek.Should().BeDefined("we want to test the failure {0}", "message"); + + // Assert + act.Should().Throw() + .WithMessage("Expected *to be defined in*failure message*, but it is not*"); + } + + [Fact] + public void A_null_entry_of_an_enum_throws() + { + // Arrange + MyEnum? subject = null; + + // Act + Action act = () => subject.Should().BeDefined(); + + // Assert + act.Should().Throw() + .WithMessage("Expected *to be defined in*, but found ."); + } + + [Fact] + public void An_invalid_entry_of_an_enum_is_not_defined_passes() + { + // Arrange + var dayOfWeek = (DayOfWeek)999; + + // Act / Assert + dayOfWeek.Should().NotBeDefined(); + } + + [Fact] + public void A_valid_entry_of_an_enum_is_not_defined_fails() + { + // Arrange + var dayOfWeek = (DayOfWeek)1; + + // Act + Action act = () => dayOfWeek.Should().NotBeDefined(); + + // Assert + act.Should().Throw() + .WithMessage("Did not expect*to be defined in*, but it is."); + } + + [Fact] + public void A_null_value_of_an_enum_is_not_defined_and_throws() + { + // Arrange + MyEnum? subject = null; + + // Act + Action act = () => subject.Should().NotBeDefined(); + + // Assert + act.Should().Throw() + .WithMessage("Did not expect *to be defined in*, but found ."); + } + #endregion } } diff --git a/docs/_pages/enums.md b/docs/_pages/enums.md index 435ac01640..3f8881b404 100644 --- a/docs/_pages/enums.md +++ b/docs/_pages/enums.md @@ -42,3 +42,11 @@ Lastly, if you want to verify than an enum has a specific integral value, you ca MyEnum.One.Should().HaveValue(1); MyEnum.One.Should().NotHaveValue(2); ``` + +```csharp +var myEnum = (MyEnum)1; +myEnum.Should().BeDefined(); + +myEnum = (MyEnum)99; +myEnum.Should().NotBeDefined(); +``` \ No newline at end of file diff --git a/docs/_pages/releases.md b/docs/_pages/releases.md index 7b586dc4e3..de4a23955d 100644 --- a/docs/_pages/releases.md +++ b/docs/_pages/releases.md @@ -9,6 +9,11 @@ sidebar: ## Unreleased +### What's new +* Add `BeDefined` and `NotBeDefined` to assert on existence of an enum value - [#1888](https://github.com/fluentassertions/fluentassertions/pull/1888) + +## 6.6.0 + ### What's New * Annotated `[Not]MatchRegex(string)` with `[StringSyntax("Regex")]` which IDEs can use to colorize the regular expression argument - [#1816](https://github.com/fluentassertions/fluentassertions/pull/1816) * Added support for .NET6 `DateOnly` struct - [#1844](https://github.com/fluentassertions/fluentassertions/pull/1844)