Skip to content

Commit 0ecec9d

Browse files
committed
Implement PhysicalFileResultAssertions. Improve the rest assertions.
1 parent 48dd387 commit 0ecec9d

File tree

9 files changed

+217
-41
lines changed

9 files changed

+217
-41
lines changed

src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ public FileResultAssertions BeFileResult()
9898
/// <summary>
9999
/// Asserts that the subject is an <see cref="FileResult"/>.
100100
/// </summary>
101+
/// <param name="reason">
102+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
103+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
104+
/// </param>
105+
/// <param name="reasonArgs">
106+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
107+
/// </param>
101108
public FileResultAssertions BeFileResult(string reason, params object[] reasonArgs)
102109
{
103110
Execute.Assertion
@@ -119,6 +126,13 @@ public FileContentResultAssertions BeFileContentResult()
119126
/// <summary>
120127
/// Asserts that the subject is an <see cref="FileContentResult"/>.
121128
/// </summary>
129+
/// <param name="reason">
130+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
131+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
132+
/// </param>
133+
/// <param name="reasonArgs">
134+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
135+
/// </param>
122136
public FileContentResultAssertions BeFileContentResult(string reason, params object[] reasonArgs)
123137
{
124138
Execute.Assertion
@@ -141,6 +155,13 @@ internal FileStreamResultAssertions BeFileStreamResult()
141155
/// <summary>
142156
/// Asserts that the subject is an <see cref="FileStreamResult"/>.
143157
/// </summary>
158+
/// <param name="reason">
159+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
160+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
161+
/// </param>
162+
/// <param name="reasonArgs">
163+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
164+
/// </param>
144165
internal FileStreamResultAssertions BeFileStreamResult(string reason, params object[] reasonArgs)
145166
{
146167
Execute.Assertion
@@ -179,6 +200,34 @@ public JsonResultAssertions BeJsonResult(string reason, params object[] reasonAr
179200
return new JsonResultAssertions(Subject as JsonResult);
180201
}
181202

203+
/// <summary>
204+
/// Asserts that the subject is an <see cref="PhysicalFileResult"/>.
205+
/// </summary>
206+
internal PhysicalFileResultAssertions BePhysicalFileResult()
207+
{
208+
return BePhysicalFileResult(string.Empty, null);
209+
}
210+
211+
/// <summary>
212+
/// Asserts that the subject is an <see cref="FileStreamResult"/>.
213+
/// </summary>
214+
/// <param name="reason">
215+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
216+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
217+
/// </param>
218+
/// <param name="reasonArgs">
219+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
220+
/// </param>
221+
internal PhysicalFileResultAssertions BePhysicalFileResult(string reason, params object[] reasonArgs)
222+
{
223+
Execute.Assertion
224+
.BecauseOf(reason, reasonArgs)
225+
.ForCondition(Subject is PhysicalFileResult)
226+
.FailWith(Constants.CommonFailMessage, typeof(PhysicalFileResult).Name, Subject.GetType().Name);
227+
228+
return new PhysicalFileResultAssertions(Subject as PhysicalFileResult);
229+
}
230+
182231
/// <summary>
183232
/// Asserts that the subject is a <see cref="RedirectToRouteResult"/>.
184233
/// </summary>

src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public FileContentResultAssertions(FileContentResult fileResult)
4040
#region Public Methods
4141

4242
/// <summary>
43-
/// Asserts that the file contents is the expected file contents.
43+
/// Asserts that the file contents is the expected bytes.
4444
/// </summary>
4545
/// <param name="expectedFileContents">The expected file contents.</param>
4646
/// <param name="reason">

src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public FileResultAssertions(FileResult fileResult)
3131
#region Public Methods
3232

3333
/// <summary>
34-
/// Asserts that the content type is the expected content type.
34+
/// Asserts that the content type is the expected string.
3535
/// </summary>
3636
/// <param name="expectedContentType">The expected content type.</param>
3737
/// <param name="reason">
@@ -77,7 +77,7 @@ public FileResultAssertions WithEntityTag(EntityTagHeaderValue expectedEntityTag
7777
}
7878

7979
/// <summary>
80-
/// Asserts that the file download name is the expected value.
80+
/// Asserts that the file download name is the expected string.
8181
/// </summary>
8282
/// <param name="expectedFileDownloadName">The expected file download name.</param>
8383
/// <param name="reason">
@@ -100,7 +100,7 @@ public FileResultAssertions WithFileDownloadName(string expectedFileDownloadName
100100
}
101101

102102
/// <summary>
103-
/// Asserts that the last modified is the expected value.
103+
/// Asserts that the last modified is the expected DateTimeOffset.
104104
/// </summary>
105105
/// <param name="expectedFileDownloadName">The expected last modified value.</param>
106106
/// <param name="reason">
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using FluentAssertions.Execution;
2+
using Microsoft.AspNetCore.Mvc;
3+
using System;
4+
using System.Diagnostics;
5+
6+
namespace FluentAssertions.AspNetCore.Mvc
7+
{
8+
/// <summary>
9+
/// Contains a number of methods to assert that a <see cref="PhysicalFileResult" /> is in the expected state.
10+
/// </summary>
11+
[DebuggerNonUserCode]
12+
public class PhysicalFileResultAssertions : FileResultAssertions
13+
{
14+
#region Public Constructors
15+
16+
public PhysicalFileResultAssertions(PhysicalFileResult fileResult)
17+
: base(fileResult)
18+
{
19+
}
20+
21+
#endregion
22+
23+
#region Public Properties
24+
25+
/// <summary>
26+
/// The <see cref="PhysicalFileResult.FileName">FileName</see> on the <see cref="PhysicalFileResult"/>
27+
/// </summary>
28+
public string FileName => PhysicalFileResultSubject.FileName;
29+
30+
#endregion Private Properties
31+
32+
#region Private Properties
33+
34+
private PhysicalFileResult PhysicalFileResultSubject => (PhysicalFileResult)Subject;
35+
36+
#endregion Private Properties
37+
38+
#region Public Methods
39+
40+
/// <summary>
41+
/// Asserts that the file name is the expected string.
42+
/// </summary>
43+
/// <param name="expectedFileName">The expected file name.</param>
44+
/// <param name="reason">
45+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
46+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
47+
/// </param>
48+
/// <param name="reasonArgs">
49+
/// Zero or more objects to format using the placeholders in <see cref="reason" />.
50+
/// </param>
51+
public FileResultAssertions WithFileName(string expectedFileName, string reason = "",
52+
params object[] reasonArgs)
53+
{
54+
var actualFileName = PhysicalFileResultSubject.FileName;
55+
56+
Execute.Assertion
57+
.ForCondition(string.Equals(expectedFileName, actualFileName, StringComparison.OrdinalIgnoreCase))
58+
.BecauseOf(reason, reasonArgs)
59+
.FailWith(FailureMessages.CommonFailMessage, "PhysicalFileResult.FileName", expectedFileName, actualFileName);
60+
return this;
61+
}
62+
63+
#endregion
64+
}
65+
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,25 @@ public void BeFileStreamResult_GivenNotFileStreamResult_ShouldFail()
103103
.WithMessage("Expected ActionResult to be \"FileStreamResult\", but found \"ViewResult\"");
104104
}
105105

106+
[Fact]
107+
public void BePhysicalFileResult_GivenPhysicalFileResult_ShouldPass()
108+
{
109+
ActionResult result = TestDataGenerator.CreatePhysicalFileResult();
110+
111+
result.Should()
112+
.BePhysicalFileResult();
113+
}
114+
115+
[Fact]
116+
public void BePhysicalFileResult_GivenNotPhysicalFileResult_ShouldFail()
117+
{
118+
ActionResult result = new ViewResult();
119+
Action a = () => result.Should().BePhysicalFileResult();
120+
121+
a.Should().Throw<Exception>()
122+
.WithMessage("Expected ActionResult to be \"PhysicalFileResult\", but found \"ViewResult\"");
123+
}
124+
106125
[Fact]
107126
public void BeJson_GivenJson_ShouldPass()
108127
{

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using FluentAssertions.AspNetCore.Mvc.Tests.Helpers;
22
using Microsoft.AspNetCore.Mvc;
33
using System;
4-
using System.Text;
54
using Xunit;
65

76
namespace FluentAssertions.AspNetCore.Mvc.Tests

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

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
using FluentAssertions.Mvc.Tests.Helpers;
1+
using FluentAssertions.AspNetCore.Mvc.Tests.Helpers;
2+
using FluentAssertions.Mvc.Tests.Helpers;
23
using Microsoft.AspNetCore.Mvc;
3-
using System;
4-
using System.Collections.Generic;
54
using Microsoft.Net.Http.Headers;
6-
using System.Text;
5+
using System;
76
using Xunit;
87

98
namespace FluentAssertions.AspNetCore.Mvc.Tests
@@ -13,17 +12,19 @@ public class FileResultAssertions_Tests
1312
[Fact]
1413
public void WithContentType_GivenExpectedValue_ShouldPass()
1514
{
16-
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain");
15+
var actualValue = "text/plain";
16+
var expectedValue = string.Copy(actualValue);
17+
ActionResult result = TestDataGenerator.CreateFileContentResult(contentType: actualValue);
1718

18-
result.Should().BeFileResult().WithContentType("text/plain");
19+
result.Should().BeFileResult().WithContentType(expectedValue);
1920
}
2021

2122
[Fact]
2223
public void WithContentType_GivenUnexpected_ShouldFail()
2324
{
2425
var actualValue = "text/css";
2526
var expectedValue = "text/plain";
26-
ActionResult result = new FileContentResult(Array.Empty<byte>(), actualValue);
27+
ActionResult result = TestDataGenerator.CreateFileContentResult(contentType: actualValue);
2728
var failureMessage = FailureMessageHelper.Format(FailureMessages.CommonFailMessage, "FileResult.ContentType", expectedValue, actualValue);
2829

2930
Action a = () => result.Should().BeFileResult().WithContentType(expectedValue);
@@ -35,10 +36,8 @@ public void WithContentType_GivenUnexpected_ShouldFail()
3536
[Fact]
3637
public void WithFileDownloadName_GivenExpectedValue_ShouldPass()
3738
{
38-
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain")
39-
{
40-
FileDownloadName = "file.txt"
41-
};
39+
var result = TestDataGenerator.CreateFileContentResult();
40+
result.FileDownloadName = "file.txt";
4241

4342
result.Should().BeFileResult().WithFileDownloadName("file.txt");
4443
}
@@ -47,11 +46,9 @@ public void WithFileDownloadName_GivenExpectedValue_ShouldPass()
4746
public void WithFileDownloadName_GivenUnexpected_ShouldFail()
4847
{
4948
var actualValue = "file2.txt";
50-
var expectedValue = "file1.txt";
51-
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain")
52-
{
53-
FileDownloadName = actualValue
54-
};
49+
var expectedValue = "file1.txt";
50+
var result = TestDataGenerator.CreateFileContentResult();
51+
result.FileDownloadName = actualValue;
5552
var failureMessage = FailureMessageHelper.Format(FailureMessages.CommonFailMessage, "FileResult.FileDownloadName", expectedValue, actualValue);
5653

5754
Action a = () => result.Should().BeFileResult().WithFileDownloadName(expectedValue);
@@ -63,10 +60,8 @@ public void WithFileDownloadName_GivenUnexpected_ShouldFail()
6360
[Fact]
6461
public void WithLastModified_GivenExpectedValue_ShouldPass()
6562
{
66-
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain")
67-
{
68-
LastModified = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00")
69-
};
63+
var result = TestDataGenerator.CreateFileContentResult();
64+
result.LastModified = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00");
7065

7166
result.Should().BeFileResult().WithLastModified(DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00"));
7267
}
@@ -76,10 +71,8 @@ public void WithLastModified_GivenUnexpected_ShouldFail()
7671
{
7772
var actualValue = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00");
7873
var expectedValue = DateTimeOffset.Parse("2010-07-16T14:46:31.0000000-06:00");
79-
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain")
80-
{
81-
LastModified = actualValue
82-
};
74+
var result = TestDataGenerator.CreateFileContentResult();
75+
result.LastModified = actualValue;
8376
var failureMessage = "Expected \"FileResult.LastModified\" to be '<2010-07-16 14:46:31 -6h>' but found '<2009-06-15 13:45:30 -7h>'";
8477

8578
Action a = () => result.Should().BeFileResult().WithLastModified(expectedValue);
@@ -94,10 +87,8 @@ public void WithEntityTag_GivenExpectedValue_ShouldPass()
9487
{
9588
var actualValue = new EntityTagHeaderValue("\"sha256 value 1\"");
9689
var expectedValue = new EntityTagHeaderValue("\"sha256 value 1\"");
97-
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain")
98-
{
99-
EntityTag = actualValue
100-
};
90+
var result = TestDataGenerator.CreateFileContentResult();
91+
result.EntityTag = actualValue;
10192

10293
result.Should().BeFileResult().WithEntityTag(expectedValue);
10394
}
@@ -107,10 +98,8 @@ public void WithEntityTag_GivenUnexpected_ShouldFail()
10798
{
10899
var actualValue = new EntityTagHeaderValue("\"sha256 value 1\"", true);
109100
var expectedValue = new EntityTagHeaderValue("\"sha256 value 2\"", false);
110-
ActionResult result = new FileContentResult(Array.Empty<byte>(), "text/plain")
111-
{
112-
EntityTag = actualValue
113-
};
101+
var result = TestDataGenerator.CreateFileContentResult();
102+
result.EntityTag = actualValue;
114103
var failureMessage = "Expected \"FileResult.EntityTag\" to be '\"sha256 value 2\"' but found 'W/\"sha256 value 1\"'";
115104

116105
Action a = () => result.Should().BeFileResult().WithEntityTag(expectedValue);

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,26 @@ namespace FluentAssertions.AspNetCore.Mvc.Tests.Helpers
66
{
77
public static class TestDataGenerator
88
{
9-
public static FileContentResult CreateFileContentResult(string content = "")
9+
public static FileContentResult CreateFileContentResult(string content = "", string contentType = "text/plain")
1010
{
11-
return CreateFileContentResult(CreateBytes(content));
11+
return CreateFileContentResult(CreateBytes(content), contentType);
1212
}
1313

14-
public static FileContentResult CreateFileContentResult(byte[] fileContents)
14+
public static FileContentResult CreateFileContentResult(byte[] fileContents, string contentType = "text/plain")
1515
{
16-
return new FileContentResult(fileContents, "text/plain");
16+
return new FileContentResult(fileContents, contentType);
1717
}
1818

1919
public static FileStreamResult CreateFileStreamResult(string content = "")
2020
{
2121
return CreateFileStreamResult(CreateStream(content));
2222
}
2323

24+
public static PhysicalFileResult CreatePhysicalFileResult(string fileName = "c:\\temp.txt")
25+
{
26+
return new PhysicalFileResult(fileName, "text/plain");
27+
}
28+
2429
public static FileStreamResult CreateFileStreamResult(Stream stream)
2530
{
2631
return new FileStreamResult(stream, "text/plain");

0 commit comments

Comments
 (0)