Skip to content

Commit 46be55d

Browse files
committed
Add ContainsFormatter To ObjectResultAssertions.
1 parent 4ab62e1 commit 46be55d

File tree

4 files changed

+160
-54
lines changed

4 files changed

+160
-54
lines changed

src/FluentAssertions.AspNetCore.Mvc/ObjectResultAssertionsBase.cs

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
using FluentAssertions.Execution;
22
using FluentAssertions.Primitives;
33
using Microsoft.AspNetCore.Mvc;
4+
using Microsoft.AspNetCore.Mvc.Formatters;
5+
using System;
46
using System.Diagnostics;
7+
using System.Linq;
8+
using System.Linq.Expressions;
59

610
namespace FluentAssertions.AspNetCore.Mvc
711
{
812
/// <summary>
913
/// Base class for <see cref="ObjectResultAssertions"/>.
1014
/// </summary>
11-
[DebuggerNonUserCode]
15+
//[DebuggerNonUserCode]
1216
public class ObjectResultAssertionsBase<TObjectResult, TObjectResultAssertion> : ObjectAssertions
1317
where TObjectResult : ObjectResult
1418
where TObjectResultAssertion : ObjectResultAssertionsBase<TObjectResult, TObjectResultAssertion>
@@ -67,6 +71,43 @@ public TValue ValueAs<TValue>()
6771

6872
return (TValue)value;
6973
}
74+
75+
/// <summary>
76+
/// Asserts that the <see cref="ObjectResult.Formatters"/> contains at least one item that matches the predicate.
77+
/// </summary>
78+
/// <param name="expectation">A predicate to match the items in the <see cref="ObjectResult.Formatters"/> against.</param>
79+
/// <param name="reason">
80+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
81+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
82+
/// </param>
83+
/// <param name="reasonArgs">
84+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
85+
/// </param>
86+
public TObjectResultAssertion ContainsFormatter(Expression<Func<IOutputFormatter, bool>> expectation, string reason = "", params object[] reasonArgs)
87+
{
88+
if (expectation is null)
89+
throw new ArgumentNullException(nameof(expectation));
90+
91+
var formatters = ObjectResultSubject.Formatters;
92+
93+
if (formatters is null)
94+
{
95+
Execute.Assertion
96+
.BecauseOf(reason, reasonArgs)
97+
.WithDefaultIdentifier(Identifier + ".Formatters")
98+
.FailWith("Expected {context} to contain {0}{reason} but found {1}.", expectation.Body, formatters);
99+
}
100+
101+
var func = expectation.Compile();
102+
103+
Execute.Assertion
104+
.ForCondition(formatters.Any(func))
105+
.WithDefaultIdentifier(Identifier+ ".Formatters")
106+
.BecauseOf(reason, reasonArgs)
107+
.FailWith("Expected {context} {0} to have an item matching {1}{reason}.", formatters, expectation.Body);
108+
109+
return (TObjectResultAssertion)this;
110+
}
70111
#endregion
71112

72113
}

tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/FailureMessageHelper.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using FluentAssertions.Formatting;
2+
using System;
23
using System.Globalization;
34
using System.Linq;
45
using System.Text;
@@ -70,6 +71,16 @@ private static object ToString(DateTimeOffset? expected)
7071
return "<null>";
7172
}
7273

74+
internal static string ExpectedToContainItemButFoundNull(string context, string predicate)
75+
{
76+
return $"Expected {context} to contain {predicate} because it is 10 but found <null>.";
77+
}
78+
79+
internal static string ExpectedToHaveItemMatching(string context, object list, string predicate)
80+
{
81+
return $"Expected {context} {Formatter.ToString(list)} to have an item matching {predicate} because it is 10.";
82+
}
83+
7384
internal static string ExpectedContextTypeXButFoundY(string context, Type expected, Type actual)
7485
{
7586
return ExpectedContextTypeXButFoundY(context, expected.FullName, actual.FullName);

tests/FluentAssertions.AspNetCore.Mvc.Tests/ObjectResultAssertionsBase_Tests.cs

-52
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using FluentAssertions.Mvc.Tests.Helpers;
3+
using Microsoft.AspNetCore.Mvc;
4+
using Microsoft.AspNetCore.Mvc.Formatters;
5+
using Moq;
6+
using Xunit;
7+
8+
namespace FluentAssertions.AspNetCore.Mvc.Tests
9+
{
10+
public class ObjectResultAssertions_Tests
11+
{
12+
private const string TestValue = "testValue";
13+
public const string Reason = FailureMessageHelper.Reason;
14+
public readonly static object[] ReasonArgs = FailureMessageHelper.ReasonArgs;
15+
16+
[Fact]
17+
public void Value_GivenObjectResult_ShouldHaveTheSameValue()
18+
{
19+
var result = new ObjectResult(TestValue);
20+
result.Should().BeObjectResult().Value.Should().BeSameAs(TestValue);
21+
}
22+
23+
[Fact]
24+
public void ValueAs_GivenObjectResult_ShouldHaveTheSameValue()
25+
{
26+
var result = new ObjectResult(TestValue);
27+
28+
result.Should().BeObjectResult().ValueAs<string>().Should().BeSameAs(TestValue);
29+
}
30+
31+
[Fact]
32+
public void ValueAs_GivenWrongType_ShouldFail()
33+
{
34+
var result = new ObjectResult(TestValue);
35+
string failureMessage = FailureMessageHelper.ExpectedContextTypeXButFoundY(
36+
"ObjectResult.Value", typeof(int), typeof(string));
37+
38+
Action a = () => result.Should().BeObjectResult().ValueAs<int>().Should().Be(2);
39+
40+
a.Should().Throw<Exception>()
41+
.WithMessage(failureMessage);
42+
}
43+
44+
[Fact]
45+
public void ValueAs_Null_ShouldFail()
46+
{
47+
ActionResult result = new ObjectResult(null);
48+
string failureMessage = FailureMessageHelper.ExpectedContextTypeXButFoundNull(
49+
"ObjectResult.Value", typeof(object));
50+
51+
Action a = () => result.Should().BeObjectResult().ValueAs<object>();
52+
53+
a.Should().Throw<Exception>()
54+
.WithMessage(failureMessage);
55+
}
56+
57+
[Fact]
58+
public void ContainsFormatter_GivenExpected_ShouldPass()
59+
{
60+
var formatterMock = new Mock<IOutputFormatter>();
61+
var result = new ObjectResult(TestValue)
62+
{
63+
Formatters = { formatterMock.Object }
64+
};
65+
66+
result.Should().BeObjectResult().ContainsFormatter(formatter => ReferenceEquals(formatter, formatterMock.Object));
67+
}
68+
69+
[Fact]
70+
public void ContainsFormatter_OnNullFormatters_ShouldFail()
71+
{
72+
var result = new ObjectResult(TestValue)
73+
{
74+
Formatters = null
75+
};
76+
string failureMessage = FailureMessageHelper.ExpectedToContainItemButFoundNull(
77+
"ObjectResult.Formatters",
78+
"(formatter == null)");
79+
80+
Action a = () => result.Should().BeObjectResult().ContainsFormatter(formatter => formatter == null, Reason, ReasonArgs);
81+
82+
a.Should().Throw<Exception>()
83+
.WithMessage(failureMessage);
84+
}
85+
86+
[Fact]
87+
public void ContainsFormatter_GivenUnexpected_ShouldFail()
88+
{
89+
var formatterMock = new Mock<IOutputFormatter>();
90+
var result = new ObjectResult(TestValue)
91+
{
92+
Formatters = { formatterMock.Object }
93+
};
94+
string failureMessage = FailureMessageHelper.ExpectedToHaveItemMatching(
95+
"ObjectResult.Formatters",
96+
result.Formatters,
97+
"False");
98+
99+
Action a = () => result.Should().BeObjectResult().ContainsFormatter(formatter => false, Reason, ReasonArgs);
100+
101+
a.Should().Throw<Exception>()
102+
.WithMessage(failureMessage);
103+
}
104+
105+
}
106+
}

0 commit comments

Comments
 (0)