Skip to content

Commit 34d32bb

Browse files
committed
Extract FileResultAssertions common method into base class.
1 parent eb30805 commit 34d32bb

File tree

9 files changed

+239
-328
lines changed

9 files changed

+239
-328
lines changed

samples/FluentAssertions.AspNetCore.Mvc.Sample/Controllers/ApiController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ public IActionResult GetPhysicalFile(string physicalPath, string contentType, st
378378
[HttpGet]
379379
public IActionResult GetVirtualFileResult(string fileName, string contentType)
380380
{
381-
return new VirtualFileResult(fileName, contentType);
381+
return File(fileName, contentType);
382382
}
383383

384384
[HttpGet]

src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ namespace FluentAssertions.AspNetCore.Mvc
99
/// Contains a number of methods to assert that a <see cref="FileContentResult" /> is in the expected state.
1010
/// </summary>>
1111
[DebuggerNonUserCode]
12-
public class FileContentResultAssertions : FileResultAssertions
12+
public class FileContentResultAssertions : FileResultAssertionsBase<FileContentResult, FileContentResultAssertions>
1313
{
1414
#region Public Constructors
1515

16+
/// <summary>
17+
/// Creates an instance of this class.
18+
/// </summary>
19+
/// <param name="fileResult">The testet instance.</param>
1620
public FileContentResultAssertions(FileContentResult fileResult)
1721
: base(fileResult)
1822
{
@@ -23,17 +27,11 @@ public FileContentResultAssertions(FileContentResult fileResult)
2327
#region Public Properties
2428

2529
/// <summary>
26-
/// The <see cref="FileContentResult.FileContents">FileContents</see> on the <see cref="FileContentResult"/>.
30+
/// The <see cref="FileContentResult.FileContents"/> on the tested subject.
2731
/// </summary>
2832
[SuppressMessage("Performance", "CA1819:Properties should not return arrays",
2933
Justification = "It needs to return the same instance as FileContentResult")]
30-
public byte[] FileContents => FileContentResultSubject.FileContents;
31-
32-
#endregion Private Properties
33-
34-
#region Private Properties
35-
36-
private FileContentResult FileContentResultSubject => (FileContentResult)Subject;
34+
public byte[] FileContents => FileResultSubject.FileContents;
3735

3836
#endregion Private Properties
3937

@@ -53,7 +51,7 @@ public FileContentResultAssertions(FileContentResult fileResult)
5351
internal FileContentResultAssertions WithFileContents(byte[] expectedFileContents, string reason = "",
5452
params object[] reasonArgs)
5553
{
56-
var actualFileContents = FileContentResultSubject.FileContents;
54+
var actualFileContents = FileResultSubject.FileContents;
5755

5856
Execute.Assertion
5957
.ForCondition(expectedFileContents.Length == actualFileContents.Length)

src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs

Lines changed: 6 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
using FluentAssertions.Execution;
2-
using FluentAssertions.Primitives;
3-
using Microsoft.AspNetCore.Mvc;
4-
using Microsoft.Net.Http.Headers;
5-
using System;
1+
using Microsoft.AspNetCore.Mvc;
62
using System.Diagnostics;
73

84
namespace FluentAssertions.AspNetCore.Mvc
@@ -11,119 +7,17 @@ namespace FluentAssertions.AspNetCore.Mvc
117
/// Contains a number of methods to assert that a <see cref="FileResult" /> is in the expected state.
128
/// </summary>
139
[DebuggerNonUserCode]
14-
public class FileResultAssertions : ObjectAssertions
10+
public class FileResultAssertions : FileResultAssertionsBase<FileResult, FileResultAssertions>
1511
{
1612
#region Public Constructors
1713

18-
public FileResultAssertions(FileResult fileResult)
19-
: base(fileResult)
20-
{
21-
}
22-
23-
#endregion
24-
25-
#region Private Properties
26-
27-
private FileResult FileResultSubject => (FileResult)Subject;
28-
29-
#endregion Private Properties
30-
31-
#region Public Methods
32-
33-
/// <summary>
34-
/// Asserts that the content type is the expected string.
35-
/// </summary>
36-
/// <param name="expectedContentType">The expected content type.</param>
37-
/// <param name="reason">
38-
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
39-
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
40-
/// </param>
41-
/// <param name="reasonArgs">
42-
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
43-
/// </param>
44-
public FileResultAssertions WithContentType(string expectedContentType, string reason = "",
45-
params object[] reasonArgs)
46-
{
47-
var actualContentType = FileResultSubject.ContentType;
48-
49-
Execute.Assertion
50-
.ForCondition(string.Equals(expectedContentType, actualContentType, StringComparison.OrdinalIgnoreCase))
51-
.BecauseOf(reason, reasonArgs)
52-
.WithDefaultIdentifier("FileResult.ContentType")
53-
.FailWith(FailureMessages.CommonFailMessage, expectedContentType, actualContentType);
54-
return this;
55-
}
56-
57-
/// <summary>
58-
/// Asserts that the entity tag is the expected value.
59-
/// </summary>
60-
/// <param name="expectedEntityTag">The expected entity tag value.</param>
61-
/// <param name="reason">
62-
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
63-
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
64-
/// </param>
65-
/// <param name="reasonArgs">
66-
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
67-
/// </param>
68-
public FileResultAssertions WithEntityTag(EntityTagHeaderValue expectedEntityTag, string reason = "",
69-
params object[] reasonArgs)
70-
{
71-
var actualEntityTag = FileResultSubject.EntityTag;
72-
73-
Execute.Assertion
74-
.ForCondition(Equals(expectedEntityTag, actualEntityTag))
75-
.BecauseOf(reason, reasonArgs)
76-
.WithDefaultIdentifier("FileResult.EntityTag")
77-
.FailWith(FailureMessages.CommonFailMessage, expectedEntityTag, actualEntityTag);
78-
return this;
79-
}
80-
81-
/// <summary>
82-
/// Asserts that the file download name is the expected string.
83-
/// </summary>
84-
/// <param name="expectedFileDownloadName">The expected file download name.</param>
85-
/// <param name="reason">
86-
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
87-
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
88-
/// </param>
89-
/// <param name="reasonArgs">
90-
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
91-
/// </param>
92-
public FileResultAssertions WithFileDownloadName(string expectedFileDownloadName, string reason = "",
93-
params object[] reasonArgs)
94-
{
95-
var actualFileDownloadName = FileResultSubject.FileDownloadName;
96-
97-
Execute.Assertion
98-
.ForCondition(string.Equals(expectedFileDownloadName, actualFileDownloadName, StringComparison.OrdinalIgnoreCase))
99-
.BecauseOf(reason, reasonArgs)
100-
.WithDefaultIdentifier("FileResult.FileDownloadName")
101-
.FailWith(FailureMessages.CommonFailMessage, expectedFileDownloadName, actualFileDownloadName);
102-
return this;
103-
}
104-
10514
/// <summary>
106-
/// Asserts that the last modified is the expected DateTimeOffset.
15+
/// Creates an instance of this class.
10716
/// </summary>
108-
/// <param name="expectedLastModified">The expected last modified value.</param>
109-
/// <param name="reason">
110-
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
111-
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
112-
/// </param>
113-
/// <param name="reasonArgs">
114-
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
115-
/// </param>
116-
public FileResultAssertions WithLastModified(DateTimeOffset? expectedLastModified, string reason = "",
117-
params object[] reasonArgs)
17+
/// <param name="fileResult">The testet instance.</param>
18+
public FileResultAssertions(FileResult fileResult)
19+
: base(fileResult)
11820
{
119-
var actualLastModified = FileResultSubject.LastModified;
120-
121-
Execute.Assertion
122-
.ForCondition(expectedLastModified == actualLastModified)
123-
.BecauseOf(reason, reasonArgs)
124-
.WithDefaultIdentifier("FileResult.LastModified")
125-
.FailWith(FailureMessages.CommonFailMessage, expectedLastModified, actualLastModified);
126-
return this;
12721
}
12822

12923
#endregion
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
using FluentAssertions.Execution;
2+
using FluentAssertions.Primitives;
3+
using Microsoft.AspNetCore.Mvc;
4+
using System;
5+
using Microsoft.Net.Http.Headers;
6+
7+
namespace FluentAssertions.AspNetCore.Mvc
8+
{
9+
/// <summary>
10+
/// Base class for <see cref="FileResultAssertions"/>, <see cref="FileContentResultAssertions"/>,
11+
/// <see cref="PhysicalFileResultAssertions"/>, <see cref="VirtualFileResultAssertions"/> and
12+
/// <see cref="FileStreamResultAssertions"/>.
13+
/// </summary>
14+
/// <typeparam name="TFileResult">The type of the testet FileResult variant.</typeparam>
15+
/// <typeparam name="TFileResultAssertions">The subclass of this class.</typeparam>
16+
public class FileResultAssertionsBase<TFileResult, TFileResultAssertions> : ObjectAssertions
17+
where TFileResult : FileResult
18+
where TFileResultAssertions : FileResultAssertionsBase<TFileResult, TFileResultAssertions>
19+
{
20+
/// <summary>
21+
/// Creates an instance of this class.
22+
/// </summary>
23+
/// <param name="fileResult">The testet instance.</param>
24+
protected FileResultAssertionsBase(TFileResult fileResult)
25+
: base(fileResult)
26+
{
27+
Identifier = typeof(TFileResult).Name;
28+
}
29+
30+
#region Private Properties
31+
32+
/// <summary>
33+
/// The <see cref="FileResult"/> under test.
34+
/// </summary>
35+
protected TFileResult FileResultSubject => (TFileResult)Subject;
36+
37+
#endregion Private Properties
38+
39+
/// <summary>
40+
/// Returns the type of the subject the assertion applies on.
41+
/// </summary>
42+
protected override string Identifier { get; }
43+
44+
#region Public Properties
45+
/// <summary>
46+
/// The <see cref="FileResult.ContentType">ContentType</see> on the <see cref="FileResult"/>.
47+
/// </summary>
48+
public string ContentType => FileResultSubject.ContentType;
49+
/// <summary>
50+
/// The <see cref="FileResult.FileDownloadName">ContentType</see> on the <see cref="FileResult"/>.
51+
/// </summary>
52+
public string FileDownloadName => FileResultSubject.FileDownloadName;
53+
/// <summary>
54+
/// The <see cref="FileResult.LastModified">ContentType</see> on the <see cref="FileResult"/>.
55+
/// </summary>
56+
public DateTimeOffset? LastModified => FileResultSubject.LastModified;
57+
/// <summary>
58+
/// The <see cref="FileResult.EntityTag">ContentType</see> on the <see cref="FileResult"/>.
59+
/// </summary>
60+
public EntityTagHeaderValue EntityTag => FileResultSubject.EntityTag;
61+
62+
#endregion
63+
64+
#region Public Methods
65+
66+
/// <summary>
67+
/// Asserts that the content type is the expected string.
68+
/// </summary>
69+
/// <param name="expectedContentType">The expected content type.</param>
70+
/// <param name="reason">
71+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
72+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
73+
/// </param>
74+
/// <param name="reasonArgs">
75+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
76+
/// </param>
77+
public TFileResultAssertions WithContentType(string expectedContentType, string reason = "",
78+
params object[] reasonArgs)
79+
{
80+
var actualContentType = FileResultSubject.ContentType;
81+
82+
Execute.Assertion
83+
.ForCondition(string.Equals(expectedContentType, actualContentType, StringComparison.OrdinalIgnoreCase))
84+
.BecauseOf(reason, reasonArgs)
85+
.WithDefaultIdentifier($"{Identifier}.ContentType")
86+
.FailWith(FailureMessages.CommonFailMessage, expectedContentType, actualContentType);
87+
return (TFileResultAssertions)this;
88+
}
89+
90+
/// <summary>
91+
/// Asserts that the entity tag is the expected value.
92+
/// </summary>
93+
/// <param name="expectedEntityTag">The expected entity tag value.</param>
94+
/// <param name="reason">
95+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
96+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
97+
/// </param>
98+
/// <param name="reasonArgs">
99+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
100+
/// </param>
101+
public TFileResultAssertions WithEntityTag(EntityTagHeaderValue expectedEntityTag, string reason = "",
102+
params object[] reasonArgs)
103+
{
104+
var actualEntityTag = FileResultSubject.EntityTag;
105+
106+
Execute.Assertion
107+
.ForCondition(Equals(expectedEntityTag, actualEntityTag))
108+
.BecauseOf(reason, reasonArgs)
109+
.WithDefaultIdentifier($"{Identifier}.EntityTag")
110+
.FailWith(FailureMessages.CommonFailMessage, expectedEntityTag, actualEntityTag);
111+
return (TFileResultAssertions)this;
112+
}
113+
114+
/// <summary>
115+
/// Asserts that the file download name is the expected string.
116+
/// </summary>
117+
/// <param name="expectedFileDownloadName">The expected file download name.</param>
118+
/// <param name="reason">
119+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
120+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
121+
/// </param>
122+
/// <param name="reasonArgs">
123+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
124+
/// </param>
125+
public TFileResultAssertions WithFileDownloadName(string expectedFileDownloadName, string reason = "",
126+
params object[] reasonArgs)
127+
{
128+
var actualFileDownloadName = FileResultSubject.FileDownloadName;
129+
130+
Execute.Assertion
131+
.ForCondition(string.Equals(expectedFileDownloadName, actualFileDownloadName, StringComparison.OrdinalIgnoreCase))
132+
.BecauseOf(reason, reasonArgs)
133+
.WithDefaultIdentifier($"{Identifier}.FileDownloadName")
134+
.FailWith(FailureMessages.CommonFailMessage, expectedFileDownloadName, actualFileDownloadName);
135+
return (TFileResultAssertions)this;
136+
}
137+
138+
/// <summary>
139+
/// Asserts that the last modified is the expected DateTimeOffset.
140+
/// </summary>
141+
/// <param name="expectedLastModified">The expected last modified value.</param>
142+
/// <param name="reason">
143+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
144+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
145+
/// </param>
146+
/// <param name="reasonArgs">
147+
/// Zero or more objects to format using the placeholders in <paramref name="reason"/>.
148+
/// </param>
149+
public TFileResultAssertions WithLastModified(DateTimeOffset? expectedLastModified, string reason = "",
150+
params object[] reasonArgs)
151+
{
152+
var actualLastModified = FileResultSubject.LastModified;
153+
154+
Execute.Assertion
155+
.ForCondition(expectedLastModified == actualLastModified)
156+
.BecauseOf(reason, reasonArgs)
157+
.WithDefaultIdentifier($"{Identifier}.LastModified")
158+
.FailWith(FailureMessages.CommonFailMessage, expectedLastModified, actualLastModified);
159+
return (TFileResultAssertions)this;
160+
}
161+
162+
#endregion
163+
}
164+
}

src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ namespace FluentAssertions.AspNetCore.Mvc
88
/// Contains a number of methods to assert that a <see cref="FileStreamResult" /> is in the expected state.
99
/// </summary>>
1010
[DebuggerNonUserCode]
11-
public class FileStreamResultAssertions : FileResultAssertions
11+
public class FileStreamResultAssertions : FileResultAssertionsBase<FileStreamResult, FileStreamResultAssertions>
1212
{
1313
#region Public Constructors
1414

15+
/// <summary>
16+
/// Creates an instance of this class.
17+
/// </summary>
18+
/// <param name="fileResult">The testet instance.</param>
1519
public FileStreamResultAssertions(FileStreamResult fileResult)
1620
: base(fileResult)
1721
{
@@ -24,15 +28,8 @@ public FileStreamResultAssertions(FileStreamResult fileResult)
2428
/// <summary>
2529
/// The <see cref="FileStreamResult.FileStream">FileStream</see> on the <see cref="FileStreamResult"/>
2630
/// </summary>
27-
public Stream FileStream => FileStreamResultSubject.FileStream;
31+
public Stream FileStream => FileResultSubject.FileStream;
2832

2933
#endregion
30-
31-
#region Private Properties
32-
33-
private FileStreamResult FileStreamResultSubject => (FileStreamResult)Subject;
34-
35-
#endregion Private Properties
36-
3734
}
3835
}

0 commit comments

Comments
 (0)