fluentassertions
fluentassertions copied to clipboard
Extend BooleanAssertions with Implies
Description
Add logical implication to the available boolean assertions.
That is, a.Should().Imply(b) asserts that a → b.
This would be useful in asserting, for example, that object equality implies hash-code equality without additional logic and a better built-in "because".
Complete minimal example
Looking for something like this.
[DataTestMethod]
[DataRow(false, false)]
[DataRow(false, true)]
// failure case: [DataRow(true, false)]
[DataRow(true, true)]
public void A_Implies_B(bool a, bool b) => a.Should().Imply(b);
Note this is logically equivalent to !a || b.
Additional Information
Also volunteering to add this.
Sorry, I don't get it.
Which part don't you get?
a → b is called implication and is read "a implies b" and is logically equivalent to !a || b.
https://en.m.wikipedia.org/wiki/Material_conditional
This is where my lack of CS degree shows ;-)
The api and implementation are both straight forward, but my immediate gut feeling is that it will only be needed/used by a few.
If you haven't done it already, you could create Imply as an extension method on BooleanAssertions in your code base.
@jnyrup i will take a look on it and try to make the extension.
@94sedighi Please wait until the API is approved before opening a PR.
Albeit a bit of a niche request, I have no issue with this proposal. It doesn't add complexity, so it should be easy to support.
Alright, then I'll approve the API addition too.
public class BooleanAssertions<TAssertions>
{
public AndConstraint<TAssertions> Imply(bool expected, string because = "", params object[] becauseArgs)
}
Is there a way to extract the expectation variable name?
This seems a little odd in the failure message:
bla.Should().Imply(blubb) would result in Expected "bla" to imply "[variable name inside the method]", but it did not.
But IMO the failure message should contain both, like: Expected "bla" to imply "blubb", but it did not.
Is there a way to extract the expectation variable name?
Not currently.
We would like to look into using [CallerArgumentExpression] for this purpose. This is listed in #1677.
Ahhm.. @94sedighi I've missed the comment where you "saved" this issue.
Sorry :)
Ahhm.. @94sedighi I've missed the comment where you "saved" this issue.
Sorry :)
Allright 😉
We would like to look into using
[CallerArgumentExpression]for this purpose.
I think we can already use that in this API
How would you add this argument?
public AndConstraint<TAssertions> Imply(bool implicator,
string because = "",
[CallerArgumentExpression("implicator")] string implicatorMessage = "",
params object[] becauseArgs)
or
public AndConstraint<TAssertions> Imply(bool implicator,
[CallerArgumentExpression("implicator")] string implicatorMessage = "",
string because = "",
params object[] becauseArgs)
Hmm.. what I can see by now: we have to go with approach 2, because if you pass becauseArgs the first one is considered as custom CallerArgumentExpression
Using approach 2 is also problematic
Writing this idiomatic FA code
subject.Should().Imply(implicator, "because we want to test the {0}", "failure");
fails with this unexpected message
Expected subject (True) to imply "because we want to test the {0}" (False) because failure, but it did not.
Ok I see. Unfortunately this param has to be optional.
What we can do? Can we force users to use this parameter?
Or maybe this only a documentation issue?
I think we should stick with the approved API, i.e. not using [CallerArgumentExpression].
Other APIs that might also benefit from having the name of the expectation, like ReferenceTypeAssertions.BeSameAs, would face the same problem.
ok.. I am fine with that.
Ok I see. Unfortunately this param has to be optional.
Ah, I see now. So yes, I agree with @jnyrup