From 856e37c4414a7d3e4aadd22d60c20a4f4a9aebe9 Mon Sep 17 00:00:00 2001 From: Viktor Faddi Date: Mon, 16 Mar 2020 18:37:37 +0100 Subject: [PATCH 1/7] Implement basic FileResultAssertions. --- .../ActionResultAssertions.cs | 21 +++ .../FileResultAssertions.cs | 119 +++++++++++++++++ .../ActionResultAssertions_Tests.cs | 35 +++++ .../FileResultAssertions_Tests.cs | 122 ++++++++++++++++++ 4 files changed, 297 insertions(+) create mode 100644 src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs create mode 100644 tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs diff --git a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs index 40eadfc..aafe4c5 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs @@ -86,6 +86,27 @@ public EmptyResult BeEmptyResult(string reason, params object[] reasonArgs) return Subject as EmptyResult; } + /// + /// Asserts that the subject is an . + /// + public FileResultAssertions BeFileResult() + { + return BeFileResult(string.Empty, null); + } + + /// + /// Asserts that the subject is an . + /// + public FileResultAssertions BeFileResult(string reason, params object[] reasonArgs) + { + Execute.Assertion + .BecauseOf(reason, reasonArgs) + .ForCondition(Subject is FileResult) + .FailWith(Constants.CommonFailMessage, typeof(FileResult).Name, Subject.GetType().Name); + + return new FileResultAssertions(Subject as FileResult); + } + /// /// Asserts that the subject is an . /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs new file mode 100644 index 0000000..f4af709 --- /dev/null +++ b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs @@ -0,0 +1,119 @@ +using FluentAssertions.Execution; +using FluentAssertions.Primitives; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; +using System; +using System.Diagnostics; + +namespace FluentAssertions.AspNetCore.Mvc +{ + /// + /// Contains a number of methods to assert that a is in the expected state. + /// + [DebuggerNonUserCode] + public class FileResultAssertions : ObjectAssertions + { + public FileResultAssertions(FileResult fileResult) + : base(fileResult) + { + } + + #region Private Properties + + private FileResult FileResultSubject => (FileResult)Subject; + + #endregion Private Properties + + /// + /// Asserts that the content type is the expected content type. + /// + /// The expected content type. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public FileResultAssertions WithContentType(string expectedContentType, string reason = "", + params object[] reasonArgs) + { + var actualContentType = FileResultSubject.ContentType; + + Execute.Assertion + .ForCondition(string.Equals(expectedContentType, actualContentType, StringComparison.OrdinalIgnoreCase)) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.CommonFailMessage, "FileResult.ContentType", expectedContentType, actualContentType); + return this; + } + + /// + /// Asserts that the entity tag is the expected value. + /// + /// The expected entity tag value. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public FileResultAssertions WithEntityTag(EntityTagHeaderValue expectedEntityTag, string reason = "", + params object[] reasonArgs) + { + var actualEntityTag = FileResultSubject.EntityTag; + + Execute.Assertion + .ForCondition(Equals(expectedEntityTag, actualEntityTag)) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.CommonFailMessage, "FileResult.EntityTag", expectedEntityTag, actualEntityTag); + return this; + } + + /// + /// Asserts that the file download name is the expected value. + /// + /// The expected file download name. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public FileResultAssertions WithFileDownloadName(string expectedFileDownloadName, string reason = "", + params object[] reasonArgs) + { + var actualFileDownloadName = FileResultSubject.FileDownloadName; + + Execute.Assertion + .ForCondition(string.Equals(expectedFileDownloadName, actualFileDownloadName, StringComparison.OrdinalIgnoreCase)) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.CommonFailMessage, "FileResult.FileDownloadName", expectedFileDownloadName, actualFileDownloadName); + return this; + } + + /// + /// Asserts that the last modified is the expected value. + /// + /// The expected last modified value. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public FileResultAssertions WithLastModified(DateTimeOffset expectedLastModified, string reason = "", + params object[] reasonArgs) + { + var actualLastModified = FileResultSubject.LastModified; + + Execute.Assertion + .ForCondition(expectedLastModified == actualLastModified) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.CommonFailMessage, "FileResult.LastModified", expectedLastModified, actualLastModified); + return this; + } + } +} diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs index 6658e00..77e542e 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs @@ -22,6 +22,7 @@ public void BeContent_GivenNotContent_ShouldFail() { ActionResult result = new ViewResult(); Action a = () => result.Should().BeContentResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"ContentResult\", but found \"ViewResult\""); } @@ -30,6 +31,7 @@ public void BeContent_GivenNotContent_ShouldFail() public void BeEmpty_GivenEmpty_ShouldPass() { ActionResult result = new EmptyResult(); + result.Should().BeEmptyResult(); } @@ -38,14 +40,36 @@ public void BeEmpty_GivenNotEmpty_ShouldPass() { ActionResult result = new ViewResult(); Action a = () => result.Should().BeEmptyResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"EmptyResult\", but found \"ViewResult\""); } + [Fact] + public void BeFileResult_GivenFileResult_ShouldPass() + { + ActionResult result = new FileContentResult(Array.Empty(), "text/plain"); + + result.Should() + .BeFileResult(); + } + + [Fact] + public void BeFileResult_GivenNotFileResult_ShouldFail() + { + ActionResult result = new ViewResult(); + Action a = () => result.Should().BeFileResult(); + + a.Should().Throw() + .WithMessage("Expected ActionResult to be \"FileResult\", but found \"ViewResult\""); + } + + [Fact] public void BeJson_GivenJson_ShouldPass() { ActionResult result = new JsonResult(new object()); + result.Should() .BeJsonResult(); } @@ -55,6 +79,7 @@ public void BeJson_GivenNotJson_ShouldFail() { ActionResult result = new ViewResult(); Action a = () => result.Should().BeJsonResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"JsonResult\", but found \"ViewResult\""); } @@ -63,6 +88,7 @@ public void BeJson_GivenNotJson_ShouldFail() public void BeRedirectToRoute_GivenRedirectToRoute_ShouldPass() { ActionResult result = new RedirectToRouteResult(new RouteValueDictionary()); + result.Should().BeRedirectToRouteResult(); } @@ -71,6 +97,7 @@ public void BeRedirectToRoute_GivenNotRedirectToRoute_ShouldFail() { ActionResult result = new ViewResult(); Action a = () => result.Should().BeRedirectToRouteResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"RedirectToRouteResult\", but found \"ViewResult\""); } @@ -79,6 +106,7 @@ public void BeRedirectToRoute_GivenNotRedirectToRoute_ShouldFail() public void BeRedirect_GivenRedirect_ShouldPass() { ActionResult result = new RedirectResult("/"); + result.Should().BeRedirectResult(); } @@ -87,6 +115,7 @@ public void BeRedirect_GivenNotRedirect_ShouldFail() { ActionResult result = new ViewResult(); Action a = () => result.Should().BeRedirectResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"RedirectResult\", but found \"ViewResult\""); } @@ -95,6 +124,7 @@ public void BeRedirect_GivenNotRedirect_ShouldFail() public void BePartialView_GivenPartial_ShouldPass() { ActionResult result = new PartialViewResult(); + result.Should().BePartialViewResult(); } @@ -103,6 +133,7 @@ public void BePartialView_GivenNotPartial_ShouldFail() { ActionResult result = new RedirectResult("/"); Action a = () => result.Should().BePartialViewResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"PartialViewResult\", but found \"RedirectResult\""); } @@ -111,6 +142,7 @@ public void BePartialView_GivenNotPartial_ShouldFail() public void BeView_GivenView_ShouldPass() { ActionResult result = new ViewResult(); + result.Should().BeViewResult(); } @@ -119,6 +151,7 @@ public void BeView_GivenNotView_ShouldFail() { ActionResult result = new RedirectResult("/"); Action a = () => result.Should().BeViewResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"ViewResult\", but found \"RedirectResult\""); } @@ -127,6 +160,7 @@ public void BeView_GivenNotView_ShouldFail() public void BeStatusCodeResult_GivenStatusCodeResult_ShouldPass() { ActionResult result = new StatusCodeResult(200); + result.Should().BeStatusCodeResult(); } @@ -135,6 +169,7 @@ public void BeStatusCodeResult_GivenNotStatusCodeResult_ShouldFail() { ActionResult result = new RedirectResult("/"); Action a = () => result.Should().BeStatusCodeResult(); + a.Should().Throw() .WithMessage("Expected ActionResult to be \"StatusCodeResult\", but found \"RedirectResult\""); } diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs new file mode 100644 index 0000000..7794130 --- /dev/null +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs @@ -0,0 +1,122 @@ +using FluentAssertions.Mvc.Tests.Helpers; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using Microsoft.Net.Http.Headers; +using System.Text; +using Xunit; + +namespace FluentAssertions.AspNetCore.Mvc.Tests +{ + public class FileResultAssertions_Tests + { + [Fact] + public void WithContentType_GivenValue_ShouldPass() + { + ActionResult result = new FileContentResult(Array.Empty(), "text/plain"); + + result.Should().BeFileResult().WithContentType("text/plain"); + } + + [Fact] + public void WithContentType_GivenUnexpected_ShouldFail() + { + var actualValue = "text/css"; + var expectedValue = "text/plain"; + ActionResult result = new FileContentResult(Array.Empty(), actualValue); + var failureMessage = FailureMessageHelper.Format(FailureMessages.CommonFailMessage, "FileResult.ContentType", expectedValue, actualValue); + + Action a = () => result.Should().BeFileResult().WithContentType(expectedValue); + + a.Should().Throw() + .WithMessage(failureMessage); + } + + [Fact] + public void WithFileDownloadName_GivenValue_ShouldPass() + { + ActionResult result = new FileContentResult(Array.Empty(), "text/plain") + { + FileDownloadName = "file.txt" + }; + + result.Should().BeFileResult().WithFileDownloadName("file.txt"); + } + + [Fact] + public void WithFileDownloadName_GivenUnexpected_ShouldFail() + { + var actualValue = "file2.txt"; + var expectedValue = "file1.txt"; + ActionResult result = new FileContentResult(Array.Empty(), "text/plain") + { + FileDownloadName = actualValue + }; + var failureMessage = FailureMessageHelper.Format(FailureMessages.CommonFailMessage, "FileResult.FileDownloadName", expectedValue, actualValue); + + Action a = () => result.Should().BeFileResult().WithFileDownloadName(expectedValue); + + a.Should().Throw() + .WithMessage(failureMessage); + } + + [Fact] + public void WithLastModified_GivenValue_ShouldPass() + { + ActionResult result = new FileContentResult(Array.Empty(), "text/plain") + { + LastModified = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00") + }; + + result.Should().BeFileResult().WithLastModified(DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00")); + } + + [Fact] + public void WithLastModified_GivenUnexpected_ShouldFail() + { + var actualValue = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00"); + var expectedValue = DateTimeOffset.Parse("2010-07-16T14:46:31.0000000-06:00"); + ActionResult result = new FileContentResult(Array.Empty(), "text/plain") + { + LastModified = actualValue + }; + var failureMessage = "Expected \"FileResult.LastModified\" to be '<2010-07-16 14:46:31 -6h>' but found '<2009-06-15 13:45:30 -7h>'"; + + Action a = () => result.Should().BeFileResult().WithLastModified(expectedValue); + + a.Should().Throw() + .WithMessage(failureMessage); + } + + + [Fact] + public void WithEntityTag_GivenValue_ShouldPass() + { + var actualValue = new EntityTagHeaderValue("\"sha256 value 1\""); + var expectedValue = new EntityTagHeaderValue("\"sha256 value 1\""); + ActionResult result = new FileContentResult(Array.Empty(), "text/plain") + { + EntityTag = actualValue + }; + + result.Should().BeFileResult().WithEntityTag(expectedValue); + } + + [Fact] + public void WithEntityTag_GivenUnexpected_ShouldFail() + { + var actualValue = new EntityTagHeaderValue("\"sha256 value 1\"", true); + var expectedValue = new EntityTagHeaderValue("\"sha256 value 2\"", false); + ActionResult result = new FileContentResult(Array.Empty(), "text/plain") + { + EntityTag = actualValue + }; + var failureMessage = "Expected \"FileResult.EntityTag\" to be '\"sha256 value 2\"' but found 'W/\"sha256 value 1\"'"; + + Action a = () => result.Should().BeFileResult().WithEntityTag(expectedValue); + + a.Should().Throw() + .WithMessage(failureMessage); + } + } +} From b17a1cdee9d4c177f243304acd331df2fb55e024 Mon Sep 17 00:00:00 2001 From: Viktor Faddi Date: Sat, 21 Mar 2020 17:11:54 +0100 Subject: [PATCH 2/7] Implement FileContentResultAssertions --- .../ActionResultAssertions.cs | 21 ++++++ .../FailureMessages.Designer.cs | 18 +++++ .../FailureMessages.resx | 6 ++ .../FileContentResultAssertions.cs | 65 +++++++++++++++++++ .../FileResultAssertions.cs | 8 +++ .../ActionResultAssertions_Tests.cs | 18 +++++ .../FileContentResultAssertions_Tests.cs | 45 +++++++++++++ .../FileResultAssertions_Tests.cs | 8 +-- .../JsonResultAssertions_Tests.cs | 4 +- 9 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs create mode 100644 tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs diff --git a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs index aafe4c5..8a963fc 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs @@ -107,6 +107,27 @@ public FileResultAssertions BeFileResult(string reason, params object[] reasonAr return new FileResultAssertions(Subject as FileResult); } + /// + /// Asserts that the subject is an . + /// + public FileContentResultAssertions BeFileContentResult() + { + return BeFileContentResult(string.Empty, null); + } + + /// + /// Asserts that the subject is an . + /// + public FileContentResultAssertions BeFileContentResult(string reason, params object[] reasonArgs) + { + Execute.Assertion + .BecauseOf(reason, reasonArgs) + .ForCondition(Subject is FileContentResult) + .FailWith(Constants.CommonFailMessage, typeof(FileContentResult).Name, Subject.GetType().Name); + + return new FileContentResultAssertions(Subject as FileContentResult); + } + /// /// Asserts that the subject is an . /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.Designer.cs b/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.Designer.cs index 06e53f2..963b618 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.Designer.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.Designer.cs @@ -87,6 +87,24 @@ internal static string CommonTypeFailMessage { } } + /// + /// Looks up a localized string similar to Expected "FileContentResult.FileContents" to have {0} byte(s), but found {1}.. + /// + internal static string FileContentResult_WithFileContents_LengthFail { + get { + return ResourceManager.GetString("FileContentResult_WithFileContents_LengthFail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected "FileContentResult.FileContents[{0}]" to be {1:x2}, but found {2:x2}.. + /// + internal static string FileContentResult_WithFileContents_MatchFail { + get { + return ResourceManager.GetString("FileContentResult_WithFileContents_MatchFail", resourceCulture); + } + } + /// /// Looks up a localized string similar to RedirectToActionResult.RouteValues does not contain key {0}.. /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.resx b/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.resx index 03209c2..6dccd97 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.resx +++ b/src/FluentAssertions.AspNetCore.Mvc/FailureMessages.resx @@ -126,6 +126,12 @@ Expected {0} to be of type '{1}' but was '{2}' + + Expected "FileContentResult.FileContents" to have {0} byte(s), but found {1}. + + + Expected "FileContentResult.FileContents[{0}]" to be {1:x2}, but found {2:x2}. + RedirectToActionResult.RouteValues does not contain key {0}. diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs new file mode 100644 index 0000000..049495c --- /dev/null +++ b/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs @@ -0,0 +1,65 @@ +using FluentAssertions.Execution; +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; + +namespace FluentAssertions.AspNetCore.Mvc +{ + /// + /// Contains a number of methods to assert that a is in the expected state. + /// > + [DebuggerNonUserCode] + public class FileContentResultAssertions : FileResultAssertions + { + #region Public Constructors + + public FileContentResultAssertions(FileContentResult fileResult) + : base(fileResult) + { + } + + #endregion + + #region Private Properties + + private FileContentResult FileContentResultSubject => (FileContentResult)Subject; + + #endregion Private Properties + + #region Public Methods + + /// + /// Asserts that the file contents is the expected file contents. + /// + /// The expected file contents. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + internal FileContentResultAssertions WithFileContents(byte[] expectedFileContents, string reason = "", + params object[] reasonArgs) + { + var actualFileContents = FileContentResultSubject.FileContents; + + Execute.Assertion + .ForCondition(expectedFileContents.Length == actualFileContents.Length) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.FileContentResult_WithFileContents_LengthFail, expectedFileContents.Length, actualFileContents.Length); + for (int i = 0; i < expectedFileContents.Length; i++) + { + var expectedByte = expectedFileContents[i]; + var actualByte = actualFileContents[i]; + Execute.Assertion + .ForCondition(expectedByte == actualByte) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.FileContentResult_WithFileContents_MatchFail, i, expectedByte, actualByte); + } + + return this; + } + + #endregion + } +} diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs index f4af709..494ad57 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs @@ -13,17 +13,23 @@ namespace FluentAssertions.AspNetCore.Mvc [DebuggerNonUserCode] public class FileResultAssertions : ObjectAssertions { + #region Public Constructors + public FileResultAssertions(FileResult fileResult) : base(fileResult) { } + #endregion + #region Private Properties private FileResult FileResultSubject => (FileResult)Subject; #endregion Private Properties + #region Public Methods + /// /// Asserts that the content type is the expected content type. /// @@ -115,5 +121,7 @@ public FileResultAssertions WithLastModified(DateTimeOffset expectedLastModified .FailWith(FailureMessages.CommonFailMessage, "FileResult.LastModified", expectedLastModified, actualLastModified); return this; } + + #endregion } } diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs index 77e542e..58e71c7 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs @@ -64,6 +64,24 @@ public void BeFileResult_GivenNotFileResult_ShouldFail() .WithMessage("Expected ActionResult to be \"FileResult\", but found \"ViewResult\""); } + [Fact] + public void BeFileContentResult_GivenFileContentResult_ShouldPass() + { + ActionResult result = new FileContentResult(Array.Empty(), "text/plain"); + + result.Should() + .BeFileContentResult(); + } + + [Fact] + public void BeFileContentResult_GivenNotFileContentResult_ShouldFail() + { + ActionResult result = new ViewResult(); + Action a = () => result.Should().BeFileContentResult(); + + a.Should().Throw() + .WithMessage("Expected ActionResult to be \"FileContentResult\", but found \"ViewResult\""); + } [Fact] public void BeJson_GivenJson_ShouldPass() diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs new file mode 100644 index 0000000..3f26a1f --- /dev/null +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Text; +using Xunit; + +namespace FluentAssertions.AspNetCore.Mvc.Tests +{ + public class FileContentResultAssertions_Tests + { + [Fact] + public void WithContentType_GivenExpectedValue_ShouldPass() + { + var actualBytes = Encoding.ASCII.GetBytes("Test 1"); + var expectedBytes = Encoding.ASCII.GetBytes("Test 1"); + ActionResult result = new FileContentResult(actualBytes, "text/plain"); + + result.Should() + .BeFileContentResult() + .WithFileContents(expectedBytes); + } + + [Theory] + [InlineData( + "Test 1", "Test 11" + , "Expected \"FileContentResult.FileContents\" to have 7 byte(s), but found 6.")] + [InlineData( + "Test 1a", "Test 2a" + , "Expected \"FileContentResult.FileContents[5]\" to be 0x32, but found 0x31.")] + public void WithContentType_GivenUnexpectedValue_ShouldFail( + string actual, string expected, string failureMessage) + { + var actualBytes = actual != null ? Encoding.ASCII.GetBytes(actual) : null; + var expectedBytes = expected != null ? Encoding.ASCII.GetBytes(expected) : null; + ActionResult result = new FileContentResult(actualBytes, "text/plain"); + + Action a = () => result.Should() + .BeFileContentResult() + .WithFileContents(expectedBytes); + + a.Should().Throw() + .WithMessage(failureMessage); + } + + } +} diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs index 7794130..e2b5057 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs @@ -11,7 +11,7 @@ namespace FluentAssertions.AspNetCore.Mvc.Tests public class FileResultAssertions_Tests { [Fact] - public void WithContentType_GivenValue_ShouldPass() + public void WithContentType_GivenExpectedValue_ShouldPass() { ActionResult result = new FileContentResult(Array.Empty(), "text/plain"); @@ -33,7 +33,7 @@ public void WithContentType_GivenUnexpected_ShouldFail() } [Fact] - public void WithFileDownloadName_GivenValue_ShouldPass() + public void WithFileDownloadName_GivenExpectedValue_ShouldPass() { ActionResult result = new FileContentResult(Array.Empty(), "text/plain") { @@ -61,7 +61,7 @@ public void WithFileDownloadName_GivenUnexpected_ShouldFail() } [Fact] - public void WithLastModified_GivenValue_ShouldPass() + public void WithLastModified_GivenExpectedValue_ShouldPass() { ActionResult result = new FileContentResult(Array.Empty(), "text/plain") { @@ -90,7 +90,7 @@ public void WithLastModified_GivenUnexpected_ShouldFail() [Fact] - public void WithEntityTag_GivenValue_ShouldPass() + public void WithEntityTag_GivenExpectedValue_ShouldPass() { var actualValue = new EntityTagHeaderValue("\"sha256 value 1\""); var expectedValue = new EntityTagHeaderValue("\"sha256 value 1\""); diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/JsonResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/JsonResultAssertions_Tests.cs index 34dc2e3..8d83c28 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/JsonResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/JsonResultAssertions_Tests.cs @@ -9,7 +9,7 @@ namespace FluentAssertions.AspNetCore.Mvc.Tests public class JsonResultAssertions_Tests { [Fact] - public void WithContentType_GivenValue_ShouldPass() + public void WithContentType_GivenExpectedValue_ShouldPass() { ActionResult result = new JsonResult("value") { @@ -37,7 +37,7 @@ public void WithContentType_GivenUnexpected_ShouldFail() } [Fact] - public void WithStatusCode_GivenValue_ShouldPass() + public void WithStatusCode_GivenExpectedValue_ShouldPass() { ActionResult result = new JsonResult("value") { From 48dd387cff5e4d752125304e7e803c79752426af Mon Sep 17 00:00:00 2001 From: Viktor Faddi Date: Sat, 21 Mar 2020 20:09:16 +0100 Subject: [PATCH 3/7] Implement FileStreamResultAssertions. (+ nicer documentation comments) --- .../ActionResultAssertions.cs | 27 +++++++++++- .../FileContentResultAssertions.cs | 12 +++++ .../FileStreamResultAssertions.cs | 39 ++++++++++++++++ .../JsonResultAssertions.cs | 4 +- .../ActionResultAssertions_Tests.cs | 24 +++++++++- .../FileContentResultAssertions_Tests.cs | 28 ++++++++---- .../FileStreamResultAssertions_Tests.cs | 23 ++++++++++ .../Helpers/TestDataGenerator.cs | 44 +++++++++++++++++++ 8 files changed, 186 insertions(+), 15 deletions(-) create mode 100644 src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs create mode 100644 tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs create mode 100644 tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs diff --git a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs index 8a963fc..e529f75 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs @@ -1,6 +1,7 @@ using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Mvc; +using System; using System.Diagnostics; namespace FluentAssertions.AspNetCore.Mvc @@ -108,7 +109,7 @@ public FileResultAssertions BeFileResult(string reason, params object[] reasonAr } /// - /// Asserts that the subject is an . + /// Asserts that the subject is an . /// public FileContentResultAssertions BeFileContentResult() { @@ -116,7 +117,7 @@ public FileContentResultAssertions BeFileContentResult() } /// - /// Asserts that the subject is an . + /// Asserts that the subject is an . /// public FileContentResultAssertions BeFileContentResult(string reason, params object[] reasonArgs) { @@ -128,6 +129,28 @@ public FileContentResultAssertions BeFileContentResult(string reason, params obj return new FileContentResultAssertions(Subject as FileContentResult); } + /// + /// Asserts that the subject is an . + /// + internal FileStreamResultAssertions BeFileStreamResult() + { + return BeFileStreamResult(string.Empty, null); + + } + + /// + /// Asserts that the subject is an . + /// + internal FileStreamResultAssertions BeFileStreamResult(string reason, params object[] reasonArgs) + { + Execute.Assertion + .BecauseOf(reason, reasonArgs) + .ForCondition(Subject is FileStreamResult) + .FailWith(Constants.CommonFailMessage, typeof(FileStreamResult).Name, Subject.GetType().Name); + + return new FileStreamResultAssertions(Subject as FileStreamResult); + } + /// /// Asserts that the subject is an . /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs index 049495c..37afc45 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs @@ -1,6 +1,7 @@ using FluentAssertions.Execution; using Microsoft.AspNetCore.Mvc; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace FluentAssertions.AspNetCore.Mvc { @@ -19,6 +20,17 @@ public FileContentResultAssertions(FileContentResult fileResult) #endregion + #region Public Properties + + /// + /// The FileContents on the . + /// + [SuppressMessage("Performance", "CA1819:Properties should not return arrays", + Justification = "It needs to return the same instance as FileContentResult")] + public byte[] FileContents => FileContentResultSubject.FileContents; + + #endregion Private Properties + #region Private Properties private FileContentResult FileContentResultSubject => (FileContentResult)Subject; diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs new file mode 100644 index 0000000..7e257bf --- /dev/null +++ b/src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs @@ -0,0 +1,39 @@ +using FluentAssertions.Execution; +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; +using System.IO; + +namespace FluentAssertions.AspNetCore.Mvc +{ + /// + /// Contains a number of methods to assert that a is in the expected state. + /// > + [DebuggerNonUserCode] + public class FileStreamResultAssertions : FileResultAssertions + { + #region Public Constructors + + public FileStreamResultAssertions(FileStreamResult fileResult) + : base(fileResult) + { + } + + #endregion + + #region Public Properties + + /// + /// The FileStream on the + /// + public Stream FileStream => FileStreamResultSubject.FileStream; + + #endregion + + #region Private Properties + + private FileStreamResult FileStreamResultSubject => (FileStreamResult)Subject; + + #endregion Private Properties + + } +} diff --git a/src/FluentAssertions.AspNetCore.Mvc/JsonResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/JsonResultAssertions.cs index 25fd404..13d6057 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/JsonResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/JsonResultAssertions.cs @@ -29,12 +29,12 @@ public JsonResultAssertions(JsonResult subject) : base(subject) #region Public Properties /// - /// The serializer settings of the JsonResult. + /// The on the . /// public JsonSerializerSettings SerializerSettings => JsonResultSubject.SerializerSettings; /// - /// The value on the JsonResult + /// The Value on the . /// public object Value => JsonResultSubject.Value; diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs index 58e71c7..7424f78 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs @@ -1,3 +1,4 @@ +using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using System; @@ -48,7 +49,7 @@ public void BeEmpty_GivenNotEmpty_ShouldPass() [Fact] public void BeFileResult_GivenFileResult_ShouldPass() { - ActionResult result = new FileContentResult(Array.Empty(), "text/plain"); + ActionResult result = TestDataGenerator.CreateFileContentResult(); result.Should() .BeFileResult(); @@ -67,7 +68,7 @@ public void BeFileResult_GivenNotFileResult_ShouldFail() [Fact] public void BeFileContentResult_GivenFileContentResult_ShouldPass() { - ActionResult result = new FileContentResult(Array.Empty(), "text/plain"); + ActionResult result = TestDataGenerator.CreateFileContentResult(); result.Should() .BeFileContentResult(); @@ -83,6 +84,25 @@ public void BeFileContentResult_GivenNotFileContentResult_ShouldFail() .WithMessage("Expected ActionResult to be \"FileContentResult\", but found \"ViewResult\""); } + [Fact] + public void BeFileStreamResult_GivenFileStreamResult_ShouldPass() + { + ActionResult result = TestDataGenerator.CreateFileStreamResult(); + + result.Should() + .BeFileStreamResult(); + } + + [Fact] + public void BeFileStreamResult_GivenNotFileStreamResult_ShouldFail() + { + ActionResult result = new ViewResult(); + Action a = () => result.Should().BeFileStreamResult(); + + a.Should().Throw() + .WithMessage("Expected ActionResult to be \"FileStreamResult\", but found \"ViewResult\""); + } + [Fact] public void BeJson_GivenJson_ShouldPass() { diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs index 3f26a1f..d8d0107 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; +using Microsoft.AspNetCore.Mvc; using System; using System.Text; using Xunit; @@ -8,11 +9,11 @@ namespace FluentAssertions.AspNetCore.Mvc.Tests public class FileContentResultAssertions_Tests { [Fact] - public void WithContentType_GivenExpectedValue_ShouldPass() + public void WithFileContents_GivenExpectedValue_ShouldPass() { - var actualBytes = Encoding.ASCII.GetBytes("Test 1"); - var expectedBytes = Encoding.ASCII.GetBytes("Test 1"); - ActionResult result = new FileContentResult(actualBytes, "text/plain"); + var actualBytes = TestDataGenerator.CreateBytes("Test 1"); + var expectedBytes = TestDataGenerator.CreateBytes("Test 1"); + ActionResult result = TestDataGenerator.CreateFileContentResult(actualBytes); result.Should() .BeFileContentResult() @@ -26,12 +27,12 @@ public void WithContentType_GivenExpectedValue_ShouldPass() [InlineData( "Test 1a", "Test 2a" , "Expected \"FileContentResult.FileContents[5]\" to be 0x32, but found 0x31.")] - public void WithContentType_GivenUnexpectedValue_ShouldFail( + public void WithFileContents_GivenUnexpectedValue_ShouldFail( string actual, string expected, string failureMessage) { - var actualBytes = actual != null ? Encoding.ASCII.GetBytes(actual) : null; - var expectedBytes = expected != null ? Encoding.ASCII.GetBytes(expected) : null; - ActionResult result = new FileContentResult(actualBytes, "text/plain"); + var actualBytes = TestDataGenerator.CreateBytes(actual); + var expectedBytes = TestDataGenerator.CreateBytes(expected); + ActionResult result = TestDataGenerator.CreateFileContentResult(actualBytes); Action a = () => result.Should() .BeFileContentResult() @@ -41,5 +42,14 @@ public void WithContentType_GivenUnexpectedValue_ShouldFail( .WithMessage(failureMessage); } + [Fact] + public void FileContents_GivenFileContentResult_ShouldHaveTheSameFileContents() + { + var result = TestDataGenerator.CreateFileContentResult(); + + result.Should() + .BeFileContentResult() + .FileContents.Should().BeSameAs(result.FileContents); + } } } diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs new file mode 100644 index 0000000..f65c3bf --- /dev/null +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs @@ -0,0 +1,23 @@ +using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; +using Microsoft.AspNetCore.Mvc; +using System; +using System.IO; +using System.Text; +using Xunit; + +namespace FluentAssertions.AspNetCore.Mvc.Tests +{ + public class FileStreamResultAssertions_Tests + { + [Fact] + public void FileStream_GivenFileStreamResult_ShouldHaveTheSameStream() + { + var result = TestDataGenerator.CreateFileStreamResult(); + + result.Should() + .BeFileStreamResult() + .FileStream + .Should().BeSameAs(result.FileStream); + } + } +} diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs new file mode 100644 index 0000000..9308254 --- /dev/null +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Mvc; +using System.IO; +using System.Text; + +namespace FluentAssertions.AspNetCore.Mvc.Tests.Helpers +{ + public static class TestDataGenerator + { + public static FileContentResult CreateFileContentResult(string content = "") + { + return CreateFileContentResult(CreateBytes(content)); + } + + public static FileContentResult CreateFileContentResult(byte[] fileContents) + { + return new FileContentResult(fileContents, "text/plain"); + } + + public static FileStreamResult CreateFileStreamResult(string content = "") + { + return CreateFileStreamResult(CreateStream(content)); + } + + public static FileStreamResult CreateFileStreamResult(Stream stream) + { + return new FileStreamResult(stream, "text/plain"); + } + + public static Stream CreateStream(string content = "") + { + var memoryStream = new MemoryStream(); + var bytes = CreateBytes(content); + memoryStream.Write(bytes, 0, bytes.Length); + memoryStream.Seek(0, SeekOrigin.Begin); + return memoryStream; + } + + public static byte[] CreateBytes(string content = "") + { + var bytes = Encoding.UTF8.GetBytes(content); + return bytes; + } + } +} From 0ecec9d572240482059505b8fc6eeb1bc8842e9f Mon Sep 17 00:00:00 2001 From: Viktor Faddi Date: Sun, 22 Mar 2020 14:04:24 +0100 Subject: [PATCH 4/7] Implement PhysicalFileResultAssertions. Improve the rest assertions. --- .../ActionResultAssertions.cs | 49 ++++++++++++++ .../FileContentResultAssertions.cs | 2 +- .../FileResultAssertions.cs | 6 +- .../PhysicalFileResultAssertions.cs | 65 +++++++++++++++++++ .../ActionResultAssertions_Tests.cs | 19 ++++++ .../FileContentResultAssertions_Tests.cs | 1 - .../FileResultAssertions_Tests.cs | 53 ++++++--------- .../Helpers/TestDataGenerator.cs | 13 ++-- .../PhysicalFileResultAssertions_Tests.cs | 50 ++++++++++++++ 9 files changed, 217 insertions(+), 41 deletions(-) create mode 100644 src/FluentAssertions.AspNetCore.Mvc/PhysicalFileResultAssertions.cs create mode 100644 tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs diff --git a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs index e529f75..20eb108 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs @@ -98,6 +98,13 @@ public FileResultAssertions BeFileResult() /// /// Asserts that the subject is an . /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// public FileResultAssertions BeFileResult(string reason, params object[] reasonArgs) { Execute.Assertion @@ -119,6 +126,13 @@ public FileContentResultAssertions BeFileContentResult() /// /// Asserts that the subject is an . /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// public FileContentResultAssertions BeFileContentResult(string reason, params object[] reasonArgs) { Execute.Assertion @@ -141,6 +155,13 @@ internal FileStreamResultAssertions BeFileStreamResult() /// /// Asserts that the subject is an . /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// internal FileStreamResultAssertions BeFileStreamResult(string reason, params object[] reasonArgs) { Execute.Assertion @@ -179,6 +200,34 @@ public JsonResultAssertions BeJsonResult(string reason, params object[] reasonAr return new JsonResultAssertions(Subject as JsonResult); } + /// + /// Asserts that the subject is an . + /// + internal PhysicalFileResultAssertions BePhysicalFileResult() + { + return BePhysicalFileResult(string.Empty, null); + } + + /// + /// Asserts that the subject is an . + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + internal PhysicalFileResultAssertions BePhysicalFileResult(string reason, params object[] reasonArgs) + { + Execute.Assertion + .BecauseOf(reason, reasonArgs) + .ForCondition(Subject is PhysicalFileResult) + .FailWith(Constants.CommonFailMessage, typeof(PhysicalFileResult).Name, Subject.GetType().Name); + + return new PhysicalFileResultAssertions(Subject as PhysicalFileResult); + } + /// /// Asserts that the subject is a . /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs index 37afc45..72e051d 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/FileContentResultAssertions.cs @@ -40,7 +40,7 @@ public FileContentResultAssertions(FileContentResult fileResult) #region Public Methods /// - /// Asserts that the file contents is the expected file contents. + /// Asserts that the file contents is the expected bytes. /// /// The expected file contents. /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs index 494ad57..3d58628 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs @@ -31,7 +31,7 @@ public FileResultAssertions(FileResult fileResult) #region Public Methods /// - /// Asserts that the content type is the expected content type. + /// Asserts that the content type is the expected string. /// /// The expected content type. /// @@ -77,7 +77,7 @@ public FileResultAssertions WithEntityTag(EntityTagHeaderValue expectedEntityTag } /// - /// Asserts that the file download name is the expected value. + /// Asserts that the file download name is the expected string. /// /// The expected file download name. /// @@ -100,7 +100,7 @@ public FileResultAssertions WithFileDownloadName(string expectedFileDownloadName } /// - /// Asserts that the last modified is the expected value. + /// Asserts that the last modified is the expected DateTimeOffset. /// /// The expected last modified value. /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/PhysicalFileResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/PhysicalFileResultAssertions.cs new file mode 100644 index 0000000..717bc5f --- /dev/null +++ b/src/FluentAssertions.AspNetCore.Mvc/PhysicalFileResultAssertions.cs @@ -0,0 +1,65 @@ +using FluentAssertions.Execution; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Diagnostics; + +namespace FluentAssertions.AspNetCore.Mvc +{ + /// + /// Contains a number of methods to assert that a is in the expected state. + /// + [DebuggerNonUserCode] + public class PhysicalFileResultAssertions : FileResultAssertions + { + #region Public Constructors + + public PhysicalFileResultAssertions(PhysicalFileResult fileResult) + : base(fileResult) + { + } + + #endregion + + #region Public Properties + + /// + /// The FileName on the + /// + public string FileName => PhysicalFileResultSubject.FileName; + + #endregion Private Properties + + #region Private Properties + + private PhysicalFileResult PhysicalFileResultSubject => (PhysicalFileResult)Subject; + + #endregion Private Properties + + #region Public Methods + + /// + /// Asserts that the file name is the expected string. + /// + /// The expected file name. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public FileResultAssertions WithFileName(string expectedFileName, string reason = "", + params object[] reasonArgs) + { + var actualFileName = PhysicalFileResultSubject.FileName; + + Execute.Assertion + .ForCondition(string.Equals(expectedFileName, actualFileName, StringComparison.OrdinalIgnoreCase)) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.CommonFailMessage, "PhysicalFileResult.FileName", expectedFileName, actualFileName); + return this; + } + + #endregion + } +} diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs index 7424f78..8399195 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs @@ -103,6 +103,25 @@ public void BeFileStreamResult_GivenNotFileStreamResult_ShouldFail() .WithMessage("Expected ActionResult to be \"FileStreamResult\", but found \"ViewResult\""); } + [Fact] + public void BePhysicalFileResult_GivenPhysicalFileResult_ShouldPass() + { + ActionResult result = TestDataGenerator.CreatePhysicalFileResult(); + + result.Should() + .BePhysicalFileResult(); + } + + [Fact] + public void BePhysicalFileResult_GivenNotPhysicalFileResult_ShouldFail() + { + ActionResult result = new ViewResult(); + Action a = () => result.Should().BePhysicalFileResult(); + + a.Should().Throw() + .WithMessage("Expected ActionResult to be \"PhysicalFileResult\", but found \"ViewResult\""); + } + [Fact] public void BeJson_GivenJson_ShouldPass() { diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs index d8d0107..21cb43a 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileContentResultAssertions_Tests.cs @@ -1,7 +1,6 @@ using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; using Microsoft.AspNetCore.Mvc; using System; -using System.Text; using Xunit; namespace FluentAssertions.AspNetCore.Mvc.Tests diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs index e2b5057..88a7925 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs @@ -1,9 +1,8 @@ -using FluentAssertions.Mvc.Tests.Helpers; +using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; +using FluentAssertions.Mvc.Tests.Helpers; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; using Microsoft.Net.Http.Headers; -using System.Text; +using System; using Xunit; namespace FluentAssertions.AspNetCore.Mvc.Tests @@ -13,9 +12,11 @@ public class FileResultAssertions_Tests [Fact] public void WithContentType_GivenExpectedValue_ShouldPass() { - ActionResult result = new FileContentResult(Array.Empty(), "text/plain"); + var actualValue = "text/plain"; + var expectedValue = string.Copy(actualValue); + ActionResult result = TestDataGenerator.CreateFileContentResult(contentType: actualValue); - result.Should().BeFileResult().WithContentType("text/plain"); + result.Should().BeFileResult().WithContentType(expectedValue); } [Fact] @@ -23,7 +24,7 @@ public void WithContentType_GivenUnexpected_ShouldFail() { var actualValue = "text/css"; var expectedValue = "text/plain"; - ActionResult result = new FileContentResult(Array.Empty(), actualValue); + ActionResult result = TestDataGenerator.CreateFileContentResult(contentType: actualValue); var failureMessage = FailureMessageHelper.Format(FailureMessages.CommonFailMessage, "FileResult.ContentType", expectedValue, actualValue); Action a = () => result.Should().BeFileResult().WithContentType(expectedValue); @@ -35,10 +36,8 @@ public void WithContentType_GivenUnexpected_ShouldFail() [Fact] public void WithFileDownloadName_GivenExpectedValue_ShouldPass() { - ActionResult result = new FileContentResult(Array.Empty(), "text/plain") - { - FileDownloadName = "file.txt" - }; + var result = TestDataGenerator.CreateFileContentResult(); + result.FileDownloadName = "file.txt"; result.Should().BeFileResult().WithFileDownloadName("file.txt"); } @@ -47,11 +46,9 @@ public void WithFileDownloadName_GivenExpectedValue_ShouldPass() public void WithFileDownloadName_GivenUnexpected_ShouldFail() { var actualValue = "file2.txt"; - var expectedValue = "file1.txt"; - ActionResult result = new FileContentResult(Array.Empty(), "text/plain") - { - FileDownloadName = actualValue - }; + var expectedValue = "file1.txt"; + var result = TestDataGenerator.CreateFileContentResult(); + result.FileDownloadName = actualValue; var failureMessage = FailureMessageHelper.Format(FailureMessages.CommonFailMessage, "FileResult.FileDownloadName", expectedValue, actualValue); Action a = () => result.Should().BeFileResult().WithFileDownloadName(expectedValue); @@ -63,10 +60,8 @@ public void WithFileDownloadName_GivenUnexpected_ShouldFail() [Fact] public void WithLastModified_GivenExpectedValue_ShouldPass() { - ActionResult result = new FileContentResult(Array.Empty(), "text/plain") - { - LastModified = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00") - }; + var result = TestDataGenerator.CreateFileContentResult(); + result.LastModified = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00"); result.Should().BeFileResult().WithLastModified(DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00")); } @@ -76,10 +71,8 @@ public void WithLastModified_GivenUnexpected_ShouldFail() { var actualValue = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00"); var expectedValue = DateTimeOffset.Parse("2010-07-16T14:46:31.0000000-06:00"); - ActionResult result = new FileContentResult(Array.Empty(), "text/plain") - { - LastModified = actualValue - }; + var result = TestDataGenerator.CreateFileContentResult(); + result.LastModified = actualValue; var failureMessage = "Expected \"FileResult.LastModified\" to be '<2010-07-16 14:46:31 -6h>' but found '<2009-06-15 13:45:30 -7h>'"; Action a = () => result.Should().BeFileResult().WithLastModified(expectedValue); @@ -94,10 +87,8 @@ public void WithEntityTag_GivenExpectedValue_ShouldPass() { var actualValue = new EntityTagHeaderValue("\"sha256 value 1\""); var expectedValue = new EntityTagHeaderValue("\"sha256 value 1\""); - ActionResult result = new FileContentResult(Array.Empty(), "text/plain") - { - EntityTag = actualValue - }; + var result = TestDataGenerator.CreateFileContentResult(); + result.EntityTag = actualValue; result.Should().BeFileResult().WithEntityTag(expectedValue); } @@ -107,10 +98,8 @@ public void WithEntityTag_GivenUnexpected_ShouldFail() { var actualValue = new EntityTagHeaderValue("\"sha256 value 1\"", true); var expectedValue = new EntityTagHeaderValue("\"sha256 value 2\"", false); - ActionResult result = new FileContentResult(Array.Empty(), "text/plain") - { - EntityTag = actualValue - }; + var result = TestDataGenerator.CreateFileContentResult(); + result.EntityTag = actualValue; var failureMessage = "Expected \"FileResult.EntityTag\" to be '\"sha256 value 2\"' but found 'W/\"sha256 value 1\"'"; Action a = () => result.Should().BeFileResult().WithEntityTag(expectedValue); diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs index 9308254..45863d5 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs @@ -6,14 +6,14 @@ namespace FluentAssertions.AspNetCore.Mvc.Tests.Helpers { public static class TestDataGenerator { - public static FileContentResult CreateFileContentResult(string content = "") + public static FileContentResult CreateFileContentResult(string content = "", string contentType = "text/plain") { - return CreateFileContentResult(CreateBytes(content)); + return CreateFileContentResult(CreateBytes(content), contentType); } - public static FileContentResult CreateFileContentResult(byte[] fileContents) + public static FileContentResult CreateFileContentResult(byte[] fileContents, string contentType = "text/plain") { - return new FileContentResult(fileContents, "text/plain"); + return new FileContentResult(fileContents, contentType); } public static FileStreamResult CreateFileStreamResult(string content = "") @@ -21,6 +21,11 @@ public static FileStreamResult CreateFileStreamResult(string content = "") return CreateFileStreamResult(CreateStream(content)); } + public static PhysicalFileResult CreatePhysicalFileResult(string fileName = "c:\\temp.txt") + { + return new PhysicalFileResult(fileName, "text/plain"); + } + public static FileStreamResult CreateFileStreamResult(Stream stream) { return new FileStreamResult(stream, "text/plain"); diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs new file mode 100644 index 0000000..9120334 --- /dev/null +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs @@ -0,0 +1,50 @@ +using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; +using Microsoft.AspNetCore.Mvc; +using System; +using Xunit; + +namespace FluentAssertions.AspNetCore.Mvc.Tests +{ + public class PhysicalFileResultAssertions_Tests + { + + [Fact] + public void WithFileName_GivenExpectedValue_ShouldPass() + { + var actualFileName = "Test1.txt"; + var expectedFileName = string.Copy(actualFileName); + ActionResult result = TestDataGenerator.CreatePhysicalFileResult(actualFileName); + + result.Should() + .BePhysicalFileResult() + .WithFileName(expectedFileName); + } + + [Fact] + public void WithFileName_GivenUnexpectedValue_ShouldFail() + { + string actualFileName = "Test1.txt"; + string expectedFileName = "Test2.txt"; + ActionResult result = TestDataGenerator.CreatePhysicalFileResult(actualFileName); + var failureMessage = "Expected \"PhysicalFileResult.FileName\" to be '\"Test2.txt\"' but found '\"Test1.txt\"'"; + + Action a = () => result.Should() + .BePhysicalFileResult() + .WithFileName(expectedFileName); + + a.Should().Throw() + .WithMessage(failureMessage); + } + + [Fact] + public void FileStream_GivenFileStreamResult_ShouldHaveTheSameStream() + { + var result = TestDataGenerator.CreatePhysicalFileResult(); + + result.Should() + .BePhysicalFileResult() + .FileName + .Should().BeSameAs(result.FileName); + } + } +} From f7adf18211446017e186be65925b8149e00f234b Mon Sep 17 00:00:00 2001 From: Viktor Faddi Date: Sun, 22 Mar 2020 14:28:51 +0100 Subject: [PATCH 5/7] Change FileResult.WithLastModified's input to nullable. --- .../FileResultAssertions.cs | 2 +- .../FileResultAssertions_Tests.cs | 25 ++++++++++++------- .../Helpers/TestDataGenerator.cs | 17 +++++++++++++ 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs index 3d58628..7917b57 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/FileResultAssertions.cs @@ -110,7 +110,7 @@ public FileResultAssertions WithFileDownloadName(string expectedFileDownloadName /// /// Zero or more objects to format using the placeholders in . /// - public FileResultAssertions WithLastModified(DateTimeOffset expectedLastModified, string reason = "", + public FileResultAssertions WithLastModified(DateTimeOffset? expectedLastModified, string reason = "", params object[] reasonArgs) { var actualLastModified = FileResultSubject.LastModified; diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs index 88a7925..38cb3a6 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileResultAssertions_Tests.cs @@ -57,23 +57,30 @@ public void WithFileDownloadName_GivenUnexpected_ShouldFail() .WithMessage(failureMessage); } - [Fact] - public void WithLastModified_GivenExpectedValue_ShouldPass() + [Theory] + [InlineData("2009-06-15 13:45:30 -7h")] + [InlineData(null)] + public void WithLastModified_GivenExpectedValue_ShouldPass(string dateText) { var result = TestDataGenerator.CreateFileContentResult(); - result.LastModified = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00"); + result.LastModified = TestDataGenerator.CreateDateTimeOffset(dateText); - result.Should().BeFileResult().WithLastModified(DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00")); + result.Should().BeFileResult() + .WithLastModified(TestDataGenerator.CreateDateTimeOffset(dateText)); } - [Fact] - public void WithLastModified_GivenUnexpected_ShouldFail() + [Theory] + [InlineData("2010-07-16 14:46:31 -6h", "2009-06-15 13:45:30 -7h")] + [InlineData(null, "2009-06-15 13:45:30 -7h")] + [InlineData("2010-07-16 14:46:31 -6h", null)] + public void WithLastModified_GivenUnexpected_ShouldFail( + string expected, string actual) { - var actualValue = DateTimeOffset.Parse("2009-06-15T13:45:30.0000000-07:00"); - var expectedValue = DateTimeOffset.Parse("2010-07-16T14:46:31.0000000-06:00"); + var actualValue = TestDataGenerator.CreateDateTimeOffset(actual); + var expectedValue = TestDataGenerator.CreateDateTimeOffset(expected); var result = TestDataGenerator.CreateFileContentResult(); result.LastModified = actualValue; - var failureMessage = "Expected \"FileResult.LastModified\" to be '<2010-07-16 14:46:31 -6h>' but found '<2009-06-15 13:45:30 -7h>'"; + var failureMessage = $"Expected \"FileResult.LastModified\" to be '<{expected ?? "null"}>' but found '<{actual ?? "null"}>'"; Action a = () => result.Should().BeFileResult().WithLastModified(expectedValue); diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs index 45863d5..e717cf9 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs @@ -1,6 +1,9 @@ using Microsoft.AspNetCore.Mvc; +using System; +using System.Globalization; using System.IO; using System.Text; +using System.Text.RegularExpressions; namespace FluentAssertions.AspNetCore.Mvc.Tests.Helpers { @@ -45,5 +48,19 @@ public static byte[] CreateBytes(string content = "") var bytes = Encoding.UTF8.GetBytes(content); return bytes; } + + public static DateTimeOffset? CreateDateTimeOffset(string dateText) + { + if (dateText == null) + return null; + var match = dateRegex.Match(dateText); + return new DateTimeOffset( + DateTime.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture), + TimeSpan.FromHours(int.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture))); + } + + private static readonly Regex dateRegex + = new Regex(@"^(\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}) (-?\d+)h$"); + } } From 61887bcb72561a2cd3559a515404386a2e87e2c0 Mon Sep 17 00:00:00 2001 From: Viktor Faddi Date: Sun, 22 Mar 2020 14:49:58 +0100 Subject: [PATCH 6/7] Implement VirtualFileResultAssertions --- .../ActionResultAssertions.cs | 60 ++++++++++++----- .../VirtualFileResultAssertions.cs | 65 +++++++++++++++++++ .../ActionResultAssertions_Tests.cs | 20 ++++++ .../Helpers/TestDataGenerator.cs | 5 ++ .../PhysicalFileResultAssertions_Tests.cs | 2 +- .../VirtualFileResultAssertions_Tests.cs | 50 ++++++++++++++ 6 files changed, 185 insertions(+), 17 deletions(-) create mode 100644 src/FluentAssertions.AspNetCore.Mvc/VirtualFileResultAssertions.cs create mode 100644 tests/FluentAssertions.AspNetCore.Mvc.Tests/VirtualFileResultAssertions_Tests.cs diff --git a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs index 20eb108..8aaf05e 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs @@ -173,15 +173,15 @@ internal FileStreamResultAssertions BeFileStreamResult(string reason, params obj } /// - /// Asserts that the subject is an . + /// Asserts that the subject is an . /// - public JsonResultAssertions BeJsonResult() + internal PhysicalFileResultAssertions BePhysicalFileResult() { - return BeJsonResult(string.Empty, null); + return BePhysicalFileResult(string.Empty, null); } /// - /// Asserts that the subject is an . + /// Asserts that the subject is an . /// /// /// A formatted phrase as is supported by explaining why the assertion @@ -190,26 +190,26 @@ public JsonResultAssertions BeJsonResult() /// /// Zero or more objects to format using the placeholders in . /// - public JsonResultAssertions BeJsonResult(string reason, params object[] reasonArgs) + internal PhysicalFileResultAssertions BePhysicalFileResult(string reason, params object[] reasonArgs) { Execute.Assertion .BecauseOf(reason, reasonArgs) - .ForCondition(Subject is JsonResult) - .FailWith(Constants.CommonFailMessage, typeof(JsonResult).Name, Subject.GetType().Name); + .ForCondition(Subject is PhysicalFileResult) + .FailWith(Constants.CommonFailMessage, typeof(PhysicalFileResult).Name, Subject.GetType().Name); - return new JsonResultAssertions(Subject as JsonResult); + return new PhysicalFileResultAssertions(Subject as PhysicalFileResult); } /// - /// Asserts that the subject is an . + /// Asserts that the subject is an . /// - internal PhysicalFileResultAssertions BePhysicalFileResult() + internal VirtualFileResultAssertions BeVirtualFileResult() { - return BePhysicalFileResult(string.Empty, null); + return BeVirtualFileResult(string.Empty, null); } /// - /// Asserts that the subject is an . + /// Asserts that the subject is an . /// /// /// A formatted phrase as is supported by explaining why the assertion @@ -218,14 +218,42 @@ internal PhysicalFileResultAssertions BePhysicalFileResult() /// /// Zero or more objects to format using the placeholders in . /// - internal PhysicalFileResultAssertions BePhysicalFileResult(string reason, params object[] reasonArgs) + internal VirtualFileResultAssertions BeVirtualFileResult(string reason, params object[] reasonArgs) { Execute.Assertion .BecauseOf(reason, reasonArgs) - .ForCondition(Subject is PhysicalFileResult) - .FailWith(Constants.CommonFailMessage, typeof(PhysicalFileResult).Name, Subject.GetType().Name); + .ForCondition(Subject is VirtualFileResult) + .FailWith(Constants.CommonFailMessage, typeof(VirtualFileResult).Name, Subject.GetType().Name); - return new PhysicalFileResultAssertions(Subject as PhysicalFileResult); + return new VirtualFileResultAssertions(Subject as VirtualFileResult); + } + + /// + /// Asserts that the subject is an . + /// + public JsonResultAssertions BeJsonResult() + { + return BeJsonResult(string.Empty, null); + } + + /// + /// Asserts that the subject is an . + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public JsonResultAssertions BeJsonResult(string reason, params object[] reasonArgs) + { + Execute.Assertion + .BecauseOf(reason, reasonArgs) + .ForCondition(Subject is JsonResult) + .FailWith(Constants.CommonFailMessage, typeof(JsonResult).Name, Subject.GetType().Name); + + return new JsonResultAssertions(Subject as JsonResult); } /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/VirtualFileResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/VirtualFileResultAssertions.cs new file mode 100644 index 0000000..36b1c07 --- /dev/null +++ b/src/FluentAssertions.AspNetCore.Mvc/VirtualFileResultAssertions.cs @@ -0,0 +1,65 @@ +using FluentAssertions.Execution; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Diagnostics; + +namespace FluentAssertions.AspNetCore.Mvc +{ + /// + /// Contains a number of methods to assert that a is in the expected state. + /// + [DebuggerNonUserCode] + public class VirtualFileResultAssertions : FileResultAssertions + { + #region Public Constructors + + public VirtualFileResultAssertions(VirtualFileResult fileResult) + : base(fileResult) + { + } + + #endregion + + #region Public Properties + + /// + /// The FileName on the + /// + public string FileName => VirtualFileResultSubject.FileName; + + #endregion Private Properties + + #region Private Properties + + private VirtualFileResult VirtualFileResultSubject => (VirtualFileResult)Subject; + + #endregion Private Properties + + #region Public Methods + + /// + /// Asserts that the file name is the expected string. + /// + /// The expected file name. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public FileResultAssertions WithFileName(string expectedFileName, string reason = "", + params object[] reasonArgs) + { + var actualFileName = VirtualFileResultSubject.FileName; + + Execute.Assertion + .ForCondition(string.Equals(expectedFileName, actualFileName, StringComparison.OrdinalIgnoreCase)) + .BecauseOf(reason, reasonArgs) + .FailWith(FailureMessages.CommonFailMessage, "VirtualFileResult.FileName", expectedFileName, actualFileName); + return this; + } + + #endregion + } +} diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs index 8399195..56ca711 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs @@ -122,6 +122,26 @@ public void BePhysicalFileResult_GivenNotPhysicalFileResult_ShouldFail() .WithMessage("Expected ActionResult to be \"PhysicalFileResult\", but found \"ViewResult\""); } + [Fact] + public void BeVirtualFileResult_GivenVirtualFileResult_ShouldPass() + { + ActionResult result = TestDataGenerator.CreateVirtualFileResult(); + + result.Should() + .BeVirtualFileResult(); + } + + [Fact] + public void BeVirtualFileResult_GivenNotVirtualFileResult_ShouldFail() + { + ActionResult result = new ViewResult(); + Action a = () => result.Should().BeVirtualFileResult(); + + a.Should().Throw() + .WithMessage("Expected ActionResult to be \"VirtualFileResult\", but found \"ViewResult\""); + } + + [Fact] public void BeJson_GivenJson_ShouldPass() { diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs index e717cf9..6aaaf2d 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/TestDataGenerator.cs @@ -29,6 +29,11 @@ public static PhysicalFileResult CreatePhysicalFileResult(string fileName = "c:\ return new PhysicalFileResult(fileName, "text/plain"); } + public static VirtualFileResult CreateVirtualFileResult(string fileName = "~/temp.txt") + { + return new VirtualFileResult(fileName, "text/plain"); + } + public static FileStreamResult CreateFileStreamResult(Stream stream) { return new FileStreamResult(stream, "text/plain"); diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs index 9120334..42fa696 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/PhysicalFileResultAssertions_Tests.cs @@ -37,7 +37,7 @@ public void WithFileName_GivenUnexpectedValue_ShouldFail() } [Fact] - public void FileStream_GivenFileStreamResult_ShouldHaveTheSameStream() + public void FileName_GivenPhysicalFileResult_ShouldHaveTheFileName() { var result = TestDataGenerator.CreatePhysicalFileResult(); diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/VirtualFileResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/VirtualFileResultAssertions_Tests.cs new file mode 100644 index 0000000..e46a973 --- /dev/null +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/VirtualFileResultAssertions_Tests.cs @@ -0,0 +1,50 @@ +using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; +using Microsoft.AspNetCore.Mvc; +using System; +using Xunit; + +namespace FluentAssertions.AspNetCore.Mvc.Tests +{ + public class VirtualFileResultAssertions_Tests + { + + [Fact] + public void WithFileName_GivenExpectedValue_ShouldPass() + { + var actualFileName = "Test1.txt"; + var expectedFileName = string.Copy(actualFileName); + ActionResult result = TestDataGenerator.CreateVirtualFileResult(actualFileName); + + result.Should() + .BeVirtualFileResult() + .WithFileName(expectedFileName); + } + + [Fact] + public void WithFileName_GivenUnexpectedValue_ShouldFail() + { + string actualFileName = "Test1.txt"; + string expectedFileName = "Test2.txt"; + ActionResult result = TestDataGenerator.CreateVirtualFileResult(actualFileName); + var failureMessage = "Expected \"VirtualFileResult.FileName\" to be '\"Test2.txt\"' but found '\"Test1.txt\"'"; + + Action a = () => result.Should() + .BeVirtualFileResult() + .WithFileName(expectedFileName); + + a.Should().Throw() + .WithMessage(failureMessage); + } + + [Fact] + public void FileName_GivenVirtualFileResult_ShouldHaveTheFileName() + { + var result = TestDataGenerator.CreateVirtualFileResult(); + + result.Should() + .BeVirtualFileResult() + .FileName + .Should().BeSameAs(result.FileName); + } + } +} From 29e3e53150446b1e6b20f1fcbba21517f98fbfb0 Mon Sep 17 00:00:00 2001 From: Viktor Faddi Date: Mon, 23 Mar 2020 21:20:41 +0100 Subject: [PATCH 7/7] namespace cleanup. --- .../ActionResultAssertions.cs | 1 - src/FluentAssertions.AspNetCore.Mvc/AssertionsExtensions.cs | 2 +- .../ContentResultAssertions.cs | 4 ++-- .../FileStreamResultAssertions.cs | 3 +-- .../PartialViewResultAssertions.cs | 4 ++-- .../RedirectResultAssertions.cs | 4 ++-- .../RedirectToActionResultAssertions.cs | 4 ++-- src/FluentAssertions.AspNetCore.Mvc/RouteDataAssertions.cs | 4 ++-- .../ContentResultAssertions_Tests.cs | 6 +++--- .../FileStreamResultAssertions_Tests.cs | 4 ---- .../Helpers/FailureMessageHelper.cs | 2 -- .../PartialViewResultAssertions_Tests.cs | 6 +++--- .../RedirectResultAssertions_Tests.cs | 6 +++--- .../RedirectToActionResultAssertions_Tests.cs | 6 +++--- 14 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs index 8aaf05e..5cb1f6b 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs @@ -1,7 +1,6 @@ using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Mvc; -using System; using System.Diagnostics; namespace FluentAssertions.AspNetCore.Mvc diff --git a/src/FluentAssertions.AspNetCore.Mvc/AssertionsExtensions.cs b/src/FluentAssertions.AspNetCore.Mvc/AssertionsExtensions.cs index 93edc5c..7324789 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/AssertionsExtensions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/AssertionsExtensions.cs @@ -1,6 +1,6 @@ -using System.Diagnostics; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using System.Diagnostics; namespace FluentAssertions.AspNetCore.Mvc { diff --git a/src/FluentAssertions.AspNetCore.Mvc/ContentResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ContentResultAssertions.cs index 33016f9..567588e 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ContentResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ContentResultAssertions.cs @@ -1,7 +1,7 @@ -using System; -using FluentAssertions.Execution; +using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Mvc; +using System; namespace FluentAssertions.AspNetCore.Mvc { diff --git a/src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs index 7e257bf..944a7cc 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/FileStreamResultAssertions.cs @@ -1,5 +1,4 @@ -using FluentAssertions.Execution; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using System.Diagnostics; using System.IO; diff --git a/src/FluentAssertions.AspNetCore.Mvc/PartialViewResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/PartialViewResultAssertions.cs index c727677..663bd54 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/PartialViewResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/PartialViewResultAssertions.cs @@ -1,7 +1,7 @@ -using System; -using FluentAssertions.Execution; +using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Mvc; +using System; namespace FluentAssertions.AspNetCore.Mvc { diff --git a/src/FluentAssertions.AspNetCore.Mvc/RedirectResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/RedirectResultAssertions.cs index f801ff0..0fba407 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/RedirectResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/RedirectResultAssertions.cs @@ -1,7 +1,7 @@ -using System; -using FluentAssertions.Execution; +using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Mvc; +using System; namespace FluentAssertions.AspNetCore.Mvc { diff --git a/src/FluentAssertions.AspNetCore.Mvc/RedirectToActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/RedirectToActionResultAssertions.cs index bc60415..8ff023a 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/RedirectToActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/RedirectToActionResultAssertions.cs @@ -1,7 +1,7 @@ -using System; -using FluentAssertions.Execution; +using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Mvc; +using System; namespace FluentAssertions.AspNetCore.Mvc { diff --git a/src/FluentAssertions.AspNetCore.Mvc/RouteDataAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/RouteDataAssertions.cs index a01bb23..fd05edd 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/RouteDataAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/RouteDataAssertions.cs @@ -1,7 +1,7 @@ -using System.Diagnostics; -using FluentAssertions.Execution; +using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Routing; +using System.Diagnostics; namespace FluentAssertions.AspNetCore.Mvc { diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ContentResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ContentResultAssertions_Tests.cs index fb60b0d..d5c9fba 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ContentResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ContentResultAssertions_Tests.cs @@ -1,10 +1,10 @@ -using System; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; +using System; using Xunit; namespace FluentAssertions.AspNetCore.Mvc.Tests { - + public class ContentResultAssertions_Tests { [Fact] diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs index f65c3bf..1d9a7a2 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/FileStreamResultAssertions_Tests.cs @@ -1,8 +1,4 @@ using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; -using Microsoft.AspNetCore.Mvc; -using System; -using System.IO; -using System.Text; using Xunit; namespace FluentAssertions.AspNetCore.Mvc.Tests diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/FailureMessageHelper.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/FailureMessageHelper.cs index 0f88101..7dd6fad 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/FailureMessageHelper.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/Helpers/FailureMessageHelper.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; namespace FluentAssertions.Mvc.Tests.Helpers { diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/PartialViewResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/PartialViewResultAssertions_Tests.cs index 4765688..ea3a358 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/PartialViewResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/PartialViewResultAssertions_Tests.cs @@ -1,11 +1,11 @@ -using System; -using FluentAssertions.Mvc.Tests.Helpers; +using FluentAssertions.Mvc.Tests.Helpers; using Microsoft.AspNetCore.Mvc; +using System; using Xunit; namespace FluentAssertions.AspNetCore.Mvc.Tests { - + public class PartialViewResultAssertions_Tests { [Fact] diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectResultAssertions_Tests.cs index c9cf484..4cdda0d 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectResultAssertions_Tests.cs @@ -1,10 +1,10 @@ -using System; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; +using System; using Xunit; namespace FluentAssertions.AspNetCore.Mvc.Tests { - + public class RedirectResultAssertions_Tests { [Fact] diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToActionResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToActionResultAssertions_Tests.cs index c01ddc4..889efa7 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToActionResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToActionResultAssertions_Tests.cs @@ -1,11 +1,11 @@ -using System; -using FluentAssertions.Mvc.Tests.Helpers; +using FluentAssertions.Mvc.Tests.Helpers; using Microsoft.AspNetCore.Mvc; +using System; using Xunit; namespace FluentAssertions.AspNetCore.Mvc.Tests { - + public class RedirectToActionResultAssertions_Tests { [Fact]