Skip to content

Commit 856e37c

Browse files
committed
Implement basic FileResultAssertions.
1 parent 61613a5 commit 856e37c

File tree

4 files changed

+297
-0
lines changed

4 files changed

+297
-0
lines changed

src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,27 @@ public EmptyResult BeEmptyResult(string reason, params object[] reasonArgs)
8686
return Subject as EmptyResult;
8787
}
8888

89+
/// <summary>
90+
/// Asserts that the subject is an <see cref="FileResult"/>.
91+
/// </summary>
92+
public FileResultAssertions BeFileResult()
93+
{
94+
return BeFileResult(string.Empty, null);
95+
}
96+
97+
/// <summary>
98+
/// Asserts that the subject is an <see cref="FileResult"/>.
99+
/// </summary>
100+
public FileResultAssertions BeFileResult(string reason, params object[] reasonArgs)
101+
{
102+
Execute.Assertion
103+
.BecauseOf(reason, reasonArgs)
104+
.ForCondition(Subject is FileResult)
105+
.FailWith(Constants.CommonFailMessage, typeof(FileResult).Name, Subject.GetType().Name);
106+
107+
return new FileResultAssertions(Subject as FileResult);
108+
}
109+
89110
/// <summary>
90111
/// Asserts that the subject is an <see cref="JsonResult"/>.
91112
/// </summary>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using FluentAssertions.Execution;
2+
using FluentAssertions.Primitives;
3+
using Microsoft.AspNetCore.Mvc;
4+
using Microsoft.Net.Http.Headers;
5+
using System;
6+
using System.Diagnostics;
7+
8+
namespace FluentAssertions.AspNetCore.Mvc
9+
{
10+
/// <summary>
11+
/// Contains a number of methods to assert that a <see cref="FileResult" /> is in the expected state.
12+
/// </summary>
13+
[DebuggerNonUserCode]
14+
public class FileResultAssertions : ObjectAssertions
15+
{
16+
public FileResultAssertions(FileResult fileResult)
17+
: base(fileResult)
18+
{
19+
}
20+
21+
#region Private Properties
22+
23+
private FileResult FileResultSubject => (FileResult)Subject;
24+
25+
#endregion Private Properties
26+
27+
/// <summary>
28+
/// Asserts that the content type is the expected content type.
29+
/// </summary>
30+
/// <param name="expectedContentType">The expected content type.</param>
31+
/// <param name="reason">
32+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
33+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
34+
/// </param>
35+
/// <param name="reasonArgs">
36+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
37+
/// </param>
38+
public FileResultAssertions WithContentType(string expectedContentType, string reason = "",
39+
params object[] reasonArgs)
40+
{
41+
var actualContentType = FileResultSubject.ContentType;
42+
43+
Execute.Assertion
44+
.ForCondition(string.Equals(expectedContentType, actualContentType, StringComparison.OrdinalIgnoreCase))
45+
.BecauseOf(reason, reasonArgs)
46+
.FailWith(FailureMessages.CommonFailMessage, "FileResult.ContentType", expectedContentType, actualContentType);
47+
return this;
48+
}
49+
50+
/// <summary>
51+
/// Asserts that the entity tag is the expected value.
52+
/// </summary>
53+
/// <param name="expectedEntityTag">The expected entity tag value.</param>
54+
/// <param name="reason">
55+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
56+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
57+
/// </param>
58+
/// <param name="reasonArgs">
59+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
60+
/// </param>
61+
public FileResultAssertions WithEntityTag(EntityTagHeaderValue expectedEntityTag, string reason = "",
62+
params object[] reasonArgs)
63+
{
64+
var actualEntityTag = FileResultSubject.EntityTag;
65+
66+
Execute.Assertion
67+
.ForCondition(Equals(expectedEntityTag, actualEntityTag))
68+
.BecauseOf(reason, reasonArgs)
69+
.FailWith(FailureMessages.CommonFailMessage, "FileResult.EntityTag", expectedEntityTag, actualEntityTag);
70+
return this;
71+
}
72+
73+
/// <summary>
74+
/// Asserts that the file download name is the expected value.
75+
/// </summary>
76+
/// <param name="expectedFileDownloadName">The expected file download name.</param>
77+
/// <param name="reason">
78+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
79+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
80+
/// </param>
81+
/// <param name="reasonArgs">
82+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
83+
/// </param>
84+
public FileResultAssertions WithFileDownloadName(string expectedFileDownloadName, string reason = "",
85+
params object[] reasonArgs)
86+
{
87+
var actualFileDownloadName = FileResultSubject.FileDownloadName;
88+
89+
Execute.Assertion
90+
.ForCondition(string.Equals(expectedFileDownloadName, actualFileDownloadName, StringComparison.OrdinalIgnoreCase))
91+
.BecauseOf(reason, reasonArgs)
92+
.FailWith(FailureMessages.CommonFailMessage, "FileResult.FileDownloadName", expectedFileDownloadName, actualFileDownloadName);
93+
return this;
94+
}
95+
96+
/// <summary>
97+
/// Asserts that the last modified is the expected value.
98+
/// </summary>
99+
/// <param name="expectedFileDownloadName">The expected last modified value.</param>
100+
/// <param name="reason">
101+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
102+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
103+
/// </param>
104+
/// <param name="reasonArgs">
105+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
106+
/// </param>
107+
public FileResultAssertions WithLastModified(DateTimeOffset expectedLastModified, string reason = "",
108+
params object[] reasonArgs)
109+
{
110+
var actualLastModified = FileResultSubject.LastModified;
111+
112+
Execute.Assertion
113+
.ForCondition(expectedLastModified == actualLastModified)
114+
.BecauseOf(reason, reasonArgs)
115+
.FailWith(FailureMessages.CommonFailMessage, "FileResult.LastModified", expectedLastModified, actualLastModified);
116+
return this;
117+
}
118+
}
119+
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public void BeContent_GivenNotContent_ShouldFail()
2222
{
2323
ActionResult result = new ViewResult();
2424
Action a = () => result.Should().BeContentResult();
25+
2526
a.Should().Throw<Exception>()
2627
.WithMessage("Expected ActionResult to be \"ContentResult\", but found \"ViewResult\"");
2728
}
@@ -30,6 +31,7 @@ public void BeContent_GivenNotContent_ShouldFail()
3031
public void BeEmpty_GivenEmpty_ShouldPass()
3132
{
3233
ActionResult result = new EmptyResult();
34+
3335
result.Should().BeEmptyResult();
3436
}
3537

@@ -38,14 +40,36 @@ public void BeEmpty_GivenNotEmpty_ShouldPass()
3840
{
3941
ActionResult result = new ViewResult();
4042
Action a = () => result.Should().BeEmptyResult();
43+
4144
a.Should().Throw<Exception>()
4245
.WithMessage("Expected ActionResult to be \"EmptyResult\", but found \"ViewResult\"");
4346
}
4447

48+
[Fact]
49+
public void BeFileResult_GivenFileResult_ShouldPass()
50+
{
51+
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain");
52+
53+
result.Should()
54+
.BeFileResult();
55+
}
56+
57+
[Fact]
58+
public void BeFileResult_GivenNotFileResult_ShouldFail()
59+
{
60+
ActionResult result = new ViewResult();
61+
Action a = () => result.Should().BeFileResult();
62+
63+
a.Should().Throw<Exception>()
64+
.WithMessage("Expected ActionResult to be \"FileResult\", but found \"ViewResult\"");
65+
}
66+
67+
4568
[Fact]
4669
public void BeJson_GivenJson_ShouldPass()
4770
{
4871
ActionResult result = new JsonResult(new object());
72+
4973
result.Should()
5074
.BeJsonResult();
5175
}
@@ -55,6 +79,7 @@ public void BeJson_GivenNotJson_ShouldFail()
5579
{
5680
ActionResult result = new ViewResult();
5781
Action a = () => result.Should().BeJsonResult();
82+
5883
a.Should().Throw<Exception>()
5984
.WithMessage("Expected ActionResult to be \"JsonResult\", but found \"ViewResult\"");
6085
}
@@ -63,6 +88,7 @@ public void BeJson_GivenNotJson_ShouldFail()
6388
public void BeRedirectToRoute_GivenRedirectToRoute_ShouldPass()
6489
{
6590
ActionResult result = new RedirectToRouteResult(new RouteValueDictionary());
91+
6692
result.Should().BeRedirectToRouteResult();
6793
}
6894

@@ -71,6 +97,7 @@ public void BeRedirectToRoute_GivenNotRedirectToRoute_ShouldFail()
7197
{
7298
ActionResult result = new ViewResult();
7399
Action a = () => result.Should().BeRedirectToRouteResult();
100+
74101
a.Should().Throw<Exception>()
75102
.WithMessage("Expected ActionResult to be \"RedirectToRouteResult\", but found \"ViewResult\"");
76103
}
@@ -79,6 +106,7 @@ public void BeRedirectToRoute_GivenNotRedirectToRoute_ShouldFail()
79106
public void BeRedirect_GivenRedirect_ShouldPass()
80107
{
81108
ActionResult result = new RedirectResult("/");
109+
82110
result.Should().BeRedirectResult();
83111
}
84112

@@ -87,6 +115,7 @@ public void BeRedirect_GivenNotRedirect_ShouldFail()
87115
{
88116
ActionResult result = new ViewResult();
89117
Action a = () => result.Should().BeRedirectResult();
118+
90119
a.Should().Throw<Exception>()
91120
.WithMessage("Expected ActionResult to be \"RedirectResult\", but found \"ViewResult\"");
92121
}
@@ -95,6 +124,7 @@ public void BeRedirect_GivenNotRedirect_ShouldFail()
95124
public void BePartialView_GivenPartial_ShouldPass()
96125
{
97126
ActionResult result = new PartialViewResult();
127+
98128
result.Should().BePartialViewResult();
99129
}
100130

@@ -103,6 +133,7 @@ public void BePartialView_GivenNotPartial_ShouldFail()
103133
{
104134
ActionResult result = new RedirectResult("/");
105135
Action a = () => result.Should().BePartialViewResult();
136+
106137
a.Should().Throw<Exception>()
107138
.WithMessage("Expected ActionResult to be \"PartialViewResult\", but found \"RedirectResult\"");
108139
}
@@ -111,6 +142,7 @@ public void BePartialView_GivenNotPartial_ShouldFail()
111142
public void BeView_GivenView_ShouldPass()
112143
{
113144
ActionResult result = new ViewResult();
145+
114146
result.Should().BeViewResult();
115147
}
116148

@@ -119,6 +151,7 @@ public void BeView_GivenNotView_ShouldFail()
119151
{
120152
ActionResult result = new RedirectResult("/");
121153
Action a = () => result.Should().BeViewResult();
154+
122155
a.Should().Throw<Exception>()
123156
.WithMessage("Expected ActionResult to be \"ViewResult\", but found \"RedirectResult\"");
124157
}
@@ -127,6 +160,7 @@ public void BeView_GivenNotView_ShouldFail()
127160
public void BeStatusCodeResult_GivenStatusCodeResult_ShouldPass()
128161
{
129162
ActionResult result = new StatusCodeResult(200);
163+
130164
result.Should().BeStatusCodeResult();
131165
}
132166

@@ -135,6 +169,7 @@ public void BeStatusCodeResult_GivenNotStatusCodeResult_ShouldFail()
135169
{
136170
ActionResult result = new RedirectResult("/");
137171
Action a = () => result.Should().BeStatusCodeResult();
172+
138173
a.Should().Throw<Exception>()
139174
.WithMessage("Expected ActionResult to be \"StatusCodeResult\", but found \"RedirectResult\"");
140175
}

0 commit comments

Comments
 (0)