From dc5c76d71c1cbe14659d4717221ecd53e7e7c7ee Mon Sep 17 00:00:00 2001 From: Juan Barahona Date: Tue, 18 May 2021 10:19:54 -0400 Subject: [PATCH 1/5] Adding implementation for RedirectResult, FileContentResult, VirtualFileResult --- src/Mvc/Mvc.Core/src/FileContentResult.cs | 43 ++++- .../Infrastructure/FileResultExecutorBase.cs | 87 ++++++---- .../VirtualFileResultExecutor.cs | 24 ++- src/Mvc/Mvc.Core/src/RedirectResult.cs | 36 +++- src/Mvc/Mvc.Core/src/Routing/UrlHelperBase.cs | 159 +++++++++--------- src/Mvc/Mvc.Core/src/VirtualFileResult.cs | 44 ++++- .../Mvc.Core/test/FileContentResultTest.cs | 75 ++++++--- src/Mvc/Mvc.Core/test/FileResultTest.cs | 24 +-- src/Mvc/Mvc.Core/test/RedirectResultTest.cs | 49 +++++- .../Mvc.Core/test/VirtualFileResultTest.cs | 111 ++++++++---- 10 files changed, 464 insertions(+), 188 deletions(-) diff --git a/src/Mvc/Mvc.Core/src/FileContentResult.cs b/src/Mvc/Mvc.Core/src/FileContentResult.cs index 7fcb8729112f..f9bc761110b6 100644 --- a/src/Mvc/Mvc.Core/src/FileContentResult.cs +++ b/src/Mvc/Mvc.Core/src/FileContentResult.cs @@ -3,9 +3,12 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Mvc @@ -14,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc /// Represents an that when executed will /// write a binary file to the response. /// - public class FileContentResult : FileResult + public class FileContentResult : FileResult, IResult { private byte[] _fileContents; @@ -77,5 +80,43 @@ public override Task ExecuteResultAsync(ActionContext context) var executor = context.HttpContext.RequestServices.GetRequiredService>(); return executor.ExecuteAsync(context, this); } + + Task IResult.ExecuteAsync(HttpContext httpContext) + { + if (httpContext == null) + { + throw new ArgumentNullException(nameof(httpContext)); + } + + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger(); + + var (range, rangeLength, serveBody) = FileResultExecutorBase.SetHeadersAndLog( + httpContext, + this, + FileContents.Length, + EnableRangeProcessing, + LastModified, + EntityTag, + logger); + + if (!serveBody) + { + return Task.CompletedTask; + } + + if (range != null && rangeLength == 0) + { + return Task.CompletedTask; + } + + if (range != null) + { + logger.WritingRangeToBody(); + } + + var fileContentStream = new MemoryStream(FileContents); + return FileResultExecutorBase.WriteFileAsyncInternal(httpContext, fileContentStream, range, rangeLength); + } } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/FileResultExecutorBase.cs b/src/Mvc/Mvc.Core/src/Infrastructure/FileResultExecutorBase.cs index c97c01cbf2ff..72dca6e2c2b5 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/FileResultExecutorBase.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/FileResultExecutorBase.cs @@ -68,16 +68,35 @@ protected virtual (RangeItemHeaderValue? range, long rangeLength, bool serveBody DateTimeOffset? lastModified = null, EntityTagHeaderValue? etag = null) { - if (context == null) + return SetHeadersAndLog( + context.HttpContext, + result, + fileLength, + enableRangeProcessing, + lastModified, + etag, + Logger); + } + + internal static (RangeItemHeaderValue? range, long rangeLength, bool serveBody) SetHeadersAndLog( + HttpContext httpContext, + FileResult result, + long? fileLength, + bool enableRangeProcessing, + DateTimeOffset? lastModified, + EntityTagHeaderValue? etag, + ILogger logger) + { + if (httpContext == null) { - throw new ArgumentNullException(nameof(context)); + throw new ArgumentNullException(nameof(httpContext)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } - - var request = context.HttpContext.Request; + + var request = httpContext.Request; var httpRequestHeaders = request.GetTypedHeaders(); // Since the 'Last-Modified' and other similar http date headers are rounded down to whole seconds, @@ -87,9 +106,9 @@ protected virtual (RangeItemHeaderValue? range, long rangeLength, bool serveBody lastModified = RoundDownToWholeSeconds(lastModified.Value); } - var preconditionState = GetPreconditionState(httpRequestHeaders, lastModified, etag); + var preconditionState = GetPreconditionState(httpRequestHeaders, lastModified, etag, logger); - var response = context.HttpContext.Response; + var response = httpContext.Response; SetLastModifiedAndEtagHeaders(response, lastModified, etag); // Short circuit if the preconditional headers process to 304 (NotModified) or 412 (PreconditionFailed) @@ -104,8 +123,8 @@ protected virtual (RangeItemHeaderValue? range, long rangeLength, bool serveBody return (range: null, rangeLength: 0, serveBody: false); } - SetContentType(context, result); - SetContentDispositionHeader(context, result); + SetContentType(httpContext, result); + SetContentDispositionHeader(httpContext, result); if (fileLength.HasValue) { @@ -125,27 +144,27 @@ protected virtual (RangeItemHeaderValue? range, long rangeLength, bool serveBody // range should be processed and Range headers should be set if ((HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method)) && (preconditionState == PreconditionState.Unspecified || preconditionState == PreconditionState.ShouldProcess) - && (IfRangeValid(httpRequestHeaders, lastModified, etag))) + && (IfRangeValid(httpRequestHeaders, lastModified, etag, logger))) { - return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value); + return SetRangeHeaders(httpContext, httpRequestHeaders, fileLength.Value, logger); } } else { - Logger.NotEnabledForRangeProcessing(); + logger.NotEnabledForRangeProcessing(); } } return (range: null, rangeLength: 0, serveBody: !HttpMethods.IsHead(request.Method)); } - private static void SetContentType(ActionContext context, FileResult result) + private static void SetContentType(HttpContext httpContext, FileResult result) { - var response = context.HttpContext.Response; + var response = httpContext.Response; response.ContentType = result.ContentType; } - private static void SetContentDispositionHeader(ActionContext context, FileResult result) + private static void SetContentDispositionHeader(HttpContext httpContext, FileResult result) { if (!string.IsNullOrEmpty(result.FileDownloadName)) { @@ -156,7 +175,7 @@ private static void SetContentDispositionHeader(ActionContext context, FileResul // basis for the actual filename, where possible. var contentDisposition = new ContentDispositionHeaderValue("attachment"); contentDisposition.SetHttpFileName(result.FileDownloadName); - context.HttpContext.Response.Headers.ContentDisposition = contentDisposition.ToString(); + httpContext.Response.Headers.ContentDisposition = contentDisposition.ToString(); } } @@ -178,10 +197,11 @@ private static void SetAcceptRangeHeader(HttpResponse response) response.Headers.AcceptRanges = AcceptRangeHeaderValue; } - internal bool IfRangeValid( + internal static bool IfRangeValid( RequestHeaders httpRequestHeaders, DateTimeOffset? lastModified, - EntityTagHeaderValue? etag) + EntityTagHeaderValue? etag, + ILogger logger) { // 14.27 If-Range var ifRange = httpRequestHeaders.IfRange; @@ -196,13 +216,13 @@ internal bool IfRangeValid( { if (lastModified.HasValue && lastModified > ifRange.LastModified) { - Logger.IfRangeLastModifiedPreconditionFailed(lastModified, ifRange.LastModified); + logger.IfRangeLastModifiedPreconditionFailed(lastModified, ifRange.LastModified); return false; } } else if (etag != null && ifRange.EntityTag != null && !ifRange.EntityTag.Compare(etag, useStrongComparison: true)) { - Logger.IfRangeETagPreconditionFailed(etag, ifRange.EntityTag); + logger.IfRangeETagPreconditionFailed(etag, ifRange.EntityTag); return false; } } @@ -211,10 +231,11 @@ internal bool IfRangeValid( } // Internal for testing - internal PreconditionState GetPreconditionState( + internal static PreconditionState GetPreconditionState( RequestHeaders httpRequestHeaders, DateTimeOffset? lastModified, - EntityTagHeaderValue? etag) + EntityTagHeaderValue? etag, + ILogger logger) { var ifMatchState = PreconditionState.Unspecified; var ifNoneMatchState = PreconditionState.Unspecified; @@ -234,7 +255,7 @@ internal PreconditionState GetPreconditionState( if (ifMatchState == PreconditionState.PreconditionFailed) { - Logger.IfMatchPreconditionFailed(etag); + logger.IfMatchPreconditionFailed(etag); } } @@ -269,7 +290,7 @@ internal PreconditionState GetPreconditionState( if (ifUnmodifiedSinceState == PreconditionState.PreconditionFailed) { - Logger.IfUnmodifiedSincePreconditionFailed(lastModified, ifUnmodifiedSince); + logger.IfUnmodifiedSincePreconditionFailed(lastModified, ifUnmodifiedSince); } } @@ -316,22 +337,23 @@ private static PreconditionState GetMaxPreconditionState(params PreconditionStat return max; } - private (RangeItemHeaderValue? range, long rangeLength, bool serveBody) SetRangeHeaders( - ActionContext context, + private static (RangeItemHeaderValue? range, long rangeLength, bool serveBody) SetRangeHeaders( + HttpContext httpContext, RequestHeaders httpRequestHeaders, - long fileLength) + long fileLength, + ILogger logger) { - var response = context.HttpContext.Response; + var response = httpContext.Response; var httpResponseHeaders = response.GetTypedHeaders(); - var serveBody = !HttpMethods.IsHead(context.HttpContext.Request.Method); + var serveBody = !HttpMethods.IsHead(httpContext.Request.Method); // Range may be null for empty range header, invalid ranges, parsing errors, multiple ranges // and when the file length is zero. var (isRangeRequest, range) = RangeHelper.ParseRange( - context.HttpContext, + httpContext, httpRequestHeaders, fileLength, - Logger); + logger); if (!isRangeRequest) { @@ -397,6 +419,11 @@ protected static ILogger CreateLogger(ILoggerFactory factory) /// The range length. /// The async task. protected static async Task WriteFileAsync(HttpContext context, Stream fileStream, RangeItemHeaderValue? range, long rangeLength) + { + await WriteFileAsyncInternal(context, fileStream, range, rangeLength); + } + + internal static async Task WriteFileAsyncInternal(HttpContext context, Stream fileStream, RangeItemHeaderValue? range, long rangeLength) { var outputStream = context.Response.Body; using (fileStream) diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs index 68e5da333b4c..3ec1178cda2d 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs @@ -50,7 +50,7 @@ public virtual Task ExecuteAsync(ActionContext context, VirtualFileResult result throw new ArgumentNullException(nameof(result)); } - var fileInfo = GetFileInformation(result); + var fileInfo = GetFileInformation(result, _hostingEnvironment); if (!fileInfo.Exists) { throw new FileNotFoundException( @@ -89,16 +89,26 @@ protected virtual Task WriteFileAsync(ActionContext context, VirtualFileResult r throw new ArgumentNullException(nameof(result)); } + return WriteFileAsyncInternal(context.HttpContext, fileInfo, range, rangeLength, Logger); + } + + internal static Task WriteFileAsyncInternal( + HttpContext httpContext, + IFileInfo fileInfo, + RangeItemHeaderValue? range, + long rangeLength, + ILogger logger) + { if (range != null && rangeLength == 0) { return Task.CompletedTask; } - var response = context.HttpContext.Response; + var response = httpContext.Response; if (range != null) { - Logger.WritingRangeToBody(); + logger.WritingRangeToBody(); } if (range != null) @@ -113,9 +123,9 @@ protected virtual Task WriteFileAsync(ActionContext context, VirtualFileResult r count: null); } - private IFileInfo GetFileInformation(VirtualFileResult result) + internal static IFileInfo GetFileInformation(VirtualFileResult result, IWebHostEnvironment hostingEnvironment) { - var fileProvider = GetFileProvider(result); + var fileProvider = GetFileProvider(result, hostingEnvironment); if (fileProvider is NullFileProvider) { throw new InvalidOperationException(Resources.VirtualFileResultExecutor_NoFileProviderConfigured); @@ -131,14 +141,14 @@ private IFileInfo GetFileInformation(VirtualFileResult result) return fileInfo; } - private IFileProvider GetFileProvider(VirtualFileResult result) + internal static IFileProvider GetFileProvider(VirtualFileResult result, IWebHostEnvironment hostingEnvironment) { if (result.FileProvider != null) { return result.FileProvider; } - result.FileProvider = _hostingEnvironment.WebRootFileProvider; + result.FileProvider = hostingEnvironment.WebRootFileProvider; return result.FileProvider; } diff --git a/src/Mvc/Mvc.Core/src/RedirectResult.cs b/src/Mvc/Mvc.Core/src/RedirectResult.cs index 22db7fc57ed1..8ce2beb6f6b4 100644 --- a/src/Mvc/Mvc.Core/src/RedirectResult.cs +++ b/src/Mvc/Mvc.Core/src/RedirectResult.cs @@ -4,10 +4,13 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Mvc { @@ -15,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc /// An that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), /// or Permanent Redirect (308) response with a Location header to the supplied URL. /// - public class RedirectResult : ActionResult, IKeepTempDataResult + public class RedirectResult : ActionResult, IResult, IKeepTempDataResult { private string _url; @@ -112,5 +115,36 @@ public override Task ExecuteResultAsync(ActionContext context) var executor = context.HttpContext.RequestServices.GetRequiredService>(); return executor.ExecuteAsync(context, this); } + + /// + Task IResult.ExecuteAsync(HttpContext httpContext) + { + if (httpContext == null) + { + throw new ArgumentNullException(nameof(httpContext)); + } + + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger(); + + // IsLocalUrl is called to handle URLs starting with '~/'. + var destinationUrl = UrlHelperBase.CheckIsLocalUrl(_url) ? UrlHelperBase.Content(httpContext, _url) : _url; + + logger.RedirectResultExecuting(destinationUrl); + + if (PreserveMethod) + { + httpContext.Response.StatusCode = Permanent + ? StatusCodes.Status308PermanentRedirect + : StatusCodes.Status307TemporaryRedirect; + httpContext.Response.Headers.Location = destinationUrl; + } + else + { + httpContext.Response.Redirect(destinationUrl, Permanent); + } + + return Task.CompletedTask; + } } } diff --git a/src/Mvc/Mvc.Core/src/Routing/UrlHelperBase.cs b/src/Mvc/Mvc.Core/src/Routing/UrlHelperBase.cs index 92a4280446ef..44717c66a27f 100644 --- a/src/Mvc/Mvc.Core/src/Routing/UrlHelperBase.cs +++ b/src/Mvc/Mvc.Core/src/Routing/UrlHelperBase.cs @@ -49,86 +49,11 @@ protected UrlHelperBase(ActionContext actionContext) public ActionContext ActionContext { get; } /// - public virtual bool IsLocalUrl([NotNullWhen(true)] string? url) - { - if (string.IsNullOrEmpty(url)) - { - return false; - } - - // Allows "/" or "/foo" but not "//" or "/\". - if (url[0] == '/') - { - // url is exactly "/" - if (url.Length == 1) - { - return true; - } - - // url doesn't start with "//" or "/\" - if (url[1] != '/' && url[1] != '\\') - { - return !HasControlCharacter(url.AsSpan(1)); - } - - return false; - } - - // Allows "~/" or "~/foo" but not "~//" or "~/\". - if (url[0] == '~' && url.Length > 1 && url[1] == '/') - { - // url is exactly "~/" - if (url.Length == 2) - { - return true; - } - - // url doesn't start with "~//" or "~/\" - if (url[2] != '/' && url[2] != '\\') - { - return !HasControlCharacter(url.AsSpan(2)); - } - - return false; - } - - return false; - - static bool HasControlCharacter(ReadOnlySpan readOnlySpan) - { - // URLs may not contain ASCII control characters. - for (var i = 0; i < readOnlySpan.Length; i++) - { - if (char.IsControl(readOnlySpan[i])) - { - return true; - } - } - - return false; - } - } + public virtual bool IsLocalUrl([NotNullWhen(true)] string? url) => CheckIsLocalUrl(url); /// [return: NotNullIfNotNull("contentPath")] - public virtual string? Content(string? contentPath) - { - if (string.IsNullOrEmpty(contentPath)) - { - return null; - } - else if (contentPath[0] == '~') - { - var segment = new PathString(contentPath.Substring(1)); - var applicationPath = ActionContext.HttpContext.Request.PathBase; - - var path = applicationPath.Add(segment); - Debug.Assert(path.HasValue); - return path.Value; - } - - return contentPath; - } + public virtual string? Content(string? contentPath) => Content(ActionContext.HttpContext, contentPath); /// public virtual string? Link(string? routeName, object? values) @@ -372,6 +297,86 @@ internal static void NormalizeRouteValuesForPage( } } + [return: NotNullIfNotNull("contentPath")] + internal static string? Content(HttpContext httpContext, string? contentPath) + { + if (string.IsNullOrEmpty(contentPath)) + { + return null; + } + else if (contentPath[0] == '~') + { + var segment = new PathString(contentPath.Substring(1)); + var applicationPath = httpContext.Request.PathBase; + + var path = applicationPath.Add(segment); + Debug.Assert(path.HasValue); + return path.Value; + } + + return contentPath; + } + + internal static bool CheckIsLocalUrl([NotNullWhen(true)] string? url) + { + if (string.IsNullOrEmpty(url)) + { + return false; + } + + // Allows "/" or "/foo" but not "//" or "/\". + if (url[0] == '/') + { + // url is exactly "/" + if (url.Length == 1) + { + return true; + } + + // url doesn't start with "//" or "/\" + if (url[1] != '/' && url[1] != '\\') + { + return !HasControlCharacter(url.AsSpan(1)); + } + + return false; + } + + // Allows "~/" or "~/foo" but not "~//" or "~/\". + if (url[0] == '~' && url.Length > 1 && url[1] == '/') + { + // url is exactly "~/" + if (url.Length == 2) + { + return true; + } + + // url doesn't start with "~//" or "~/\" + if (url[2] != '/' && url[2] != '\\') + { + return !HasControlCharacter(url.AsSpan(2)); + } + + return false; + } + + return false; + + static bool HasControlCharacter(ReadOnlySpan readOnlySpan) + { + // URLs may not contain ASCII control characters. + for (var i = 0; i < readOnlySpan.Length; i++) + { + if (char.IsControl(readOnlySpan[i])) + { + return true; + } + } + + return false; + } + } + private static object CalculatePageName(ActionContext? context, RouteValueDictionary? ambientValues, string pageName) { Debug.Assert(pageName.Length > 0); diff --git a/src/Mvc/Mvc.Core/src/VirtualFileResult.cs b/src/Mvc/Mvc.Core/src/VirtualFileResult.cs index 7d49d9de41de..ac95c84a07eb 100644 --- a/src/Mvc/Mvc.Core/src/VirtualFileResult.cs +++ b/src/Mvc/Mvc.Core/src/VirtualFileResult.cs @@ -3,10 +3,15 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Mvc @@ -15,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc /// A that on execution writes the file specified using a virtual path to the response /// using mechanisms provided by the host. /// - public class VirtualFileResult : FileResult + public class VirtualFileResult : FileResult, IResult { private string _fileName; @@ -69,5 +74,42 @@ public override Task ExecuteResultAsync(ActionContext context) var executor = context.HttpContext.RequestServices.GetRequiredService>(); return executor.ExecuteAsync(context, this); } + + Task IResult.ExecuteAsync(HttpContext httpContext) + { + if (httpContext == null) + { + throw new ArgumentNullException(nameof(httpContext)); + } + + var hostingEnvironment = httpContext.RequestServices.GetRequiredService(); + + var fileInfo = VirtualFileResultExecutor.GetFileInformation(this, hostingEnvironment); + if (!fileInfo.Exists) + { + throw new FileNotFoundException( + Resources.FormatFileResult_InvalidPath(FileName), FileName); + } + + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger(); + + var lastModified = LastModified ?? fileInfo.LastModified; + var (range, rangeLength, serveBody) = FileResultExecutorBase.SetHeadersAndLog( + httpContext, + this, + fileInfo.Length, + EnableRangeProcessing, + lastModified, + EntityTag, + logger); + + if (serveBody) + { + return VirtualFileResultExecutor.WriteFileAsyncInternal(httpContext, fileInfo, range, rangeLength, logger); + } + + return Task.CompletedTask; + } } } diff --git a/src/Mvc/Mvc.Core/test/FileContentResultTest.cs b/src/Mvc/Mvc.Core/test/FileContentResultTest.cs index 77380a55755c..966e72db81e4 100644 --- a/src/Mvc/Mvc.Core/test/FileContentResultTest.cs +++ b/src/Mvc/Mvc.Core/test/FileContentResultTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; @@ -71,8 +72,11 @@ public void Constructor_SetsLastModifiedAndEtag() MediaTypeAssert.Equal(expectedMediaType, result.ContentType); } - [Fact] - public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_CopiesBuffer_ToOutputStream( + string action, + Func function) { // Arrange var buffer = new byte[] { 1, 2, 3, 4, 5 }; @@ -87,7 +91,7 @@ public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() var result = new FileContentResult(buffer, "text/plain"); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert Assert.Equal(buffer, outStream.ToArray()); @@ -144,8 +148,11 @@ public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeReque Assert.Equal(expectedString, body); } - [Fact] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -173,7 +180,7 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -200,8 +207,11 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest() } } - [Fact] - public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored( + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -228,7 +238,7 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -241,8 +251,11 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored() Assert.Equal("Hello World", body); } - [Fact] - public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored( + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -270,7 +283,7 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -365,8 +378,11 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotS Assert.Empty(body); } - [Fact] - public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored( + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -393,7 +409,7 @@ public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -407,8 +423,11 @@ public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored() Assert.Empty(body); } - [Fact] - public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_NotModified_RangeRequestedIgnored( + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -435,7 +454,7 @@ public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -450,8 +469,11 @@ public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() Assert.Empty(body); } - [Fact] - public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + string action, + Func function) { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; @@ -467,13 +489,22 @@ public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() var result = new FileContentResult(buffer, expectedContentType); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert Assert.Equal(buffer, outStream.ToArray()); Assert.Equal(expectedContentType, httpContext.Response.ContentType); } + public static IEnumerable GetActions() + { + return new List + { + new object[] { "ActionContext", new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)) }, + new object[] { "HttpContext", new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)) }, + }; + } + private static IServiceCollection CreateServices() { var services = new ServiceCollection(); @@ -493,4 +524,4 @@ private static HttpContext GetHttpContext() return httpContext; } } -} \ No newline at end of file +} diff --git a/src/Mvc/Mvc.Core/test/FileResultTest.cs b/src/Mvc/Mvc.Core/test/FileResultTest.cs index 07967adc1eda..25e6d6f3634e 100644 --- a/src/Mvc/Mvc.Core/test/FileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/FileResultTest.cs @@ -268,13 +268,13 @@ public void GetPreconditionState_ShouldProcess(string ifMatch, string ifNoneMatc httpRequestHeaders.IfUnmodifiedSince = lastModified; httpRequestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(1); actionContext.HttpContext = httpContext; - var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var state = fileResult.GetPreconditionState( + var state = FileResultExecutorBase.GetPreconditionState( httpRequestHeaders, lastModified, - etag); + etag, + NullLogger.Instance); // Assert Assert.Equal(FileResultExecutorBase.PreconditionState.ShouldProcess, state); @@ -307,13 +307,13 @@ public void GetPreconditionState_ShouldNotProcess_PreconditionFailed(string ifMa httpRequestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue; httpRequestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(2); actionContext.HttpContext = httpContext; - var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var state = fileResult.GetPreconditionState( + var state = FileResultExecutorBase.GetPreconditionState( httpRequestHeaders, lastModified, - etag); + etag, + NullLogger.Instance); // Assert Assert.Equal(FileResultExecutorBase.PreconditionState.PreconditionFailed, state); @@ -344,13 +344,13 @@ public void GetPreconditionState_ShouldNotProcess_NotModified(string ifMatch, st }; httpRequestHeaders.IfModifiedSince = lastModified; actionContext.HttpContext = httpContext; - var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var state = fileResult.GetPreconditionState( + var state = FileResultExecutorBase.GetPreconditionState( httpRequestHeaders, lastModified, - etag); + etag, + NullLogger.Instance); // Assert Assert.Equal(FileResultExecutorBase.PreconditionState.NotModified, state); @@ -372,13 +372,13 @@ public void IfRangeValid_IgnoreRangeRequest(string ifRangeString, bool expected) httpRequestHeaders.IfRange = new RangeConditionHeaderValue(ifRangeString); httpRequestHeaders.IfModifiedSince = lastModified; actionContext.HttpContext = httpContext; - var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var ifRangeIsValid = fileResult.IfRangeValid( + var ifRangeIsValid = FileResultExecutorBase.IfRangeValid( httpRequestHeaders, lastModified, - etag); + etag, + NullLogger.Instance); // Assert Assert.Equal(expected, ifRangeIsValid); diff --git a/src/Mvc/Mvc.Core/test/RedirectResultTest.cs b/src/Mvc/Mvc.Core/test/RedirectResultTest.cs index 481245fee89d..06ec9cf8d87b 100644 --- a/src/Mvc/Mvc.Core/test/RedirectResultTest.cs +++ b/src/Mvc/Mvc.Core/test/RedirectResultTest.cs @@ -4,14 +4,12 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Headers; using Moq; using Xunit; @@ -111,6 +109,51 @@ public async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); } + [Theory] + [InlineData("", "/Home/About", "/Home/About")] + [InlineData("/myapproot", "/test", "/test")] + public async Task ResultExecute_ReturnsContentPath_WhenItDoesNotStartWithTilde( + string appRoot, + string contentPath, + string expectedPath) + { + // Arrange + var httpContext = GetHttpContext(appRoot); + IResult result = new RedirectResult(contentPath); + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + // Verifying if Redirect was called with the specific Url and parameter flag. + Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); + Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); + } + + [Theory] + [InlineData(null, "~/Home/About", "/Home/About")] + [InlineData("/", "~/Home/About", "/Home/About")] + [InlineData("/", "~/", "/")] + [InlineData("", "~/Home/About", "/Home/About")] + [InlineData("/myapproot", "~/", "/myapproot/")] + public async Task ResultExecute_ReturnsAppRelativePath_WhenItStartsWithTilde( + string appRoot, + string contentPath, + string expectedPath) + { + // Arrange + var httpContext = GetHttpContext(appRoot); + IResult result = new RedirectResult(contentPath); + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + // Verifying if Redirect was called with the specific Url and parameter flag. + Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); + Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); + } + private static ActionContext GetActionContext(HttpContext httpContext) { var routeData = new RouteData(); @@ -139,4 +182,4 @@ private static HttpContext GetHttpContext( return httpContext; } } -} \ No newline at end of file +} diff --git a/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs b/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs index 6d4ecfe35150..832bcc2acd61 100644 --- a/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.IO; using System.IO.Pipelines; using System.Text; @@ -103,8 +104,11 @@ public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, st Assert.Equal((long?)contentLength, sendFileFeature.Length); } - [Fact] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( + string action, + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -133,7 +137,7 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -148,8 +152,11 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() Assert.Equal(4, sendFileFeature.Length); } - [Fact] - public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( + string action, + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -177,7 +184,7 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -188,8 +195,11 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored Assert.Null(sendFileFeature.Length); } - [Fact] - public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( + string action, + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -218,7 +228,7 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -318,8 +328,11 @@ public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString Assert.Empty(body); } - [Fact] - public async Task WriteFileAsync_RangeRequested_PreconditionFailed() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_RangeRequested_PreconditionFailed( + string action, + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -346,7 +359,7 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -357,8 +370,11 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed() Assert.Null(sendFileFeature.Name); // Not called } - [Fact] - public async Task WriteFileAsync_RangeRequested_NotModified() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_RangeRequested_NotModified( + string action, + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -385,7 +401,7 @@ public async Task WriteFileAsync_RangeRequested_NotModified() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -397,8 +413,11 @@ public async Task WriteFileAsync_RangeRequested_NotModified() Assert.Null(sendFileFeature.Name); // Not called } - [Fact] - public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent( + string action, + Func function) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); @@ -419,7 +438,7 @@ public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProv var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert Assert.Equal(path, sendFileFeature.Name); @@ -427,8 +446,11 @@ public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProv Assert.Null(sendFileFeature.Length); } - [Fact] - public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( + string action, + Func function) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); @@ -447,7 +469,7 @@ public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert sendFileMock.Verify(); @@ -506,8 +528,11 @@ public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHtt Assert.Equal(contentLength, httpResponse.ContentLength); } - [Fact] - public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + string action, + Func function) { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; @@ -523,15 +548,18 @@ public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert Assert.Equal(expectedContentType, httpContext.Response.ContentType); Assert.Equal("FilePathResultTestFile_ASCII.txt", sendFileFeature.Name); } - [Fact] - public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths( + string action, + Func function) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); @@ -546,7 +574,7 @@ public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert Assert.Equal(path, sendFileFeature.Name); @@ -610,8 +638,11 @@ public async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(strin Assert.Equal(expectedPath, sendFileFeature.Name); } - [Fact] - public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles( + string action, + Func function) { // Arrange var httpContext = GetHttpContext(typeof(VirtualFileResultExecutor)); @@ -633,7 +664,7 @@ public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles() }; // Act - await filePathResult.ExecuteResultAsync(actionContext); + await function(filePathResult, action == "ActionContext" ? actionContext : httpContext); // Assert httpContext.Response.Body.Position = 0; @@ -641,8 +672,11 @@ public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles() Assert.Equal(expectedData, contents); } - [Fact] - public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile( + string action, + Func function) { // Arrange var path = "TestPath.txt"; @@ -659,13 +693,22 @@ public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFind var context = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); // Act - var ex = await Assert.ThrowsAsync(() => filePathResult.ExecuteResultAsync(context)); + var ex = await Assert.ThrowsAsync(() => function(filePathResult, action == "ActionContext" ? context : context.HttpContext)); // Assert Assert.Equal(expectedMessage, ex.Message); Assert.Equal(path, ex.FileName); } + public static IEnumerable GetActions() + { + return new List + { + new object[] { "ActionContext", new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)) }, + new object[] { "HttpContext", new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)) }, + }; + } + private static IServiceCollection CreateServices(Type executorType) { var services = new ServiceCollection(); @@ -770,4 +813,4 @@ public Task StartAsync(CancellationToken cancellation = default) } } } -} \ No newline at end of file +} From 48c3948783f9c2a0a98b6a1515d620ac8c67fe5d Mon Sep 17 00:00:00 2001 From: Juan Barahona Date: Tue, 18 May 2021 21:22:03 -0400 Subject: [PATCH 2/5] Adding Physical implemenation and tests --- src/Mvc/Mvc.Core/src/FileStreamResult.cs | 8 +- .../PhysicalFileResultExecutor.cs | 20 ++-- src/Mvc/Mvc.Core/src/PhysicalFileResult.cs | 52 +++++++++- .../Mvc.Core/test/PhysicalFileResultTest.cs | 94 +++++++++++++------ 4 files changed, 139 insertions(+), 35 deletions(-) diff --git a/src/Mvc/Mvc.Core/src/FileStreamResult.cs b/src/Mvc/Mvc.Core/src/FileStreamResult.cs index ba358eeb09c4..3fb885fa3d17 100644 --- a/src/Mvc/Mvc.Core/src/FileStreamResult.cs +++ b/src/Mvc/Mvc.Core/src/FileStreamResult.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc /// Represents an that when executed will /// write a file from a stream to the response. /// - public class FileStreamResult : FileResult + public class FileStreamResult : FileResult, IResult { private Stream _fileStream; @@ -79,5 +80,10 @@ public override Task ExecuteResultAsync(ActionContext context) var executor = context.HttpContext.RequestServices.GetRequiredService>(); return executor.ExecuteAsync(context, this); } + + Task IResult.ExecuteAsync(HttpContext httpContext) + { + throw new NotImplementedException(); + } } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs index 7d1b5cfa161d..f295d2769f77 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs @@ -3,10 +3,8 @@ using System; using System.IO; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; @@ -69,9 +67,19 @@ public virtual Task ExecuteAsync(ActionContext context, PhysicalFileResult resul /// protected virtual Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue? range, long rangeLength) { - if (context == null) + return WriteFileAsyncInternal(context.HttpContext, result, range, rangeLength, Logger); + } + + internal static Task WriteFileAsyncInternal( + HttpContext httpContext, + PhysicalFileResult result, + RangeItemHeaderValue? range, + long rangeLength, + ILogger logger) + { + if (httpContext == null) { - throw new ArgumentNullException(nameof(context)); + throw new ArgumentNullException(nameof(httpContext)); } if (result == null) @@ -84,7 +92,7 @@ protected virtual Task WriteFileAsync(ActionContext context, PhysicalFileResult return Task.CompletedTask; } - var response = context.HttpContext.Response; + var response = httpContext.Response; if (!Path.IsPathRooted(result.FileName)) { throw new NotSupportedException(Resources.FormatFileResult_PathNotRooted(result.FileName)); @@ -92,7 +100,7 @@ protected virtual Task WriteFileAsync(ActionContext context, PhysicalFileResult if (range != null) { - Logger.WritingRangeToBody(); + logger.WritingRangeToBody(); } if (range != null) diff --git a/src/Mvc/Mvc.Core/src/PhysicalFileResult.cs b/src/Mvc/Mvc.Core/src/PhysicalFileResult.cs index def6a2b65408..9734ddbacdfe 100644 --- a/src/Mvc/Mvc.Core/src/PhysicalFileResult.cs +++ b/src/Mvc/Mvc.Core/src/PhysicalFileResult.cs @@ -3,9 +3,13 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Mvc @@ -14,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc /// A on execution will write a file from disk to the response /// using mechanisms provided by the host. /// - public class PhysicalFileResult : FileResult + public class PhysicalFileResult : FileResult, IResult { private string _fileName; @@ -66,5 +70,51 @@ public override Task ExecuteResultAsync(ActionContext context) var executor = context.HttpContext.RequestServices.GetRequiredService>(); return executor.ExecuteAsync(context, this); } + + Task IResult.ExecuteAsync(HttpContext httpContext) + { + if (httpContext == null) + { + throw new ArgumentNullException(nameof(httpContext)); + } + + var fileInfo = new FileInfo(FileName); + if (!fileInfo.Exists) + { + throw new FileNotFoundException( + Resources.FormatFileResult_InvalidPath(FileName), FileName); + } + + return ExecuteAsyncInternal(httpContext, this, fileInfo.LastWriteTimeUtc, fileInfo.Length); + } + + internal static Task ExecuteAsyncInternal( + HttpContext httpContext, + PhysicalFileResult result, + DateTimeOffset fileLastModified, + long fileLength) + { + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger(); + + logger.ExecutingFileResult(result, result.FileName); + + var lastModified = result.LastModified ?? fileLastModified; + var (range, rangeLength, serveBody) = FileResultExecutorBase.SetHeadersAndLog( + httpContext, + result, + fileLength, + result.EnableRangeProcessing, + lastModified, + result.EntityTag, + logger); + + if (serveBody) + { + return PhysicalFileResultExecutor.WriteFileAsyncInternal(httpContext, result, range, rangeLength, logger); + } + + return Task.CompletedTask; + } } } diff --git a/src/Mvc/Mvc.Core/test/PhysicalFileResultTest.cs b/src/Mvc/Mvc.Core/test/PhysicalFileResultTest.cs index 8d29080dd204..caa9635d97e6 100644 --- a/src/Mvc/Mvc.Core/test/PhysicalFileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/PhysicalFileResultTest.cs @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.IO; using System.IO.Pipelines; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -90,8 +90,11 @@ public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, st Assert.Equal((long?)contentLength, sendFile.Length); } - [Fact] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -109,7 +112,7 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -125,8 +128,11 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() Assert.Equal(4, sendFile.Length); } - [Fact] - public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -143,7 +149,7 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -154,8 +160,11 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored Assert.Null(sendFile.Length); } - [Fact] - public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -173,7 +182,7 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -249,8 +258,11 @@ public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString Assert.Empty(body); } - [Fact] - public async Task WriteFileAsync_RangeRequested_PreconditionFailed() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_RangeRequested_PreconditionFailed( + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -265,7 +277,7 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -279,8 +291,11 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed() Assert.Empty(body); } - [Fact] - public async Task WriteFileAsync_RangeRequested_NotModified() + [Theory] + [MemberData(nameof(GetActions))] + public async Task WriteFileAsync_RangeRequested_NotModified( + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -295,7 +310,7 @@ public async Task WriteFileAsync_RangeRequested_NotModified() var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -310,8 +325,11 @@ public async Task WriteFileAsync_RangeRequested_NotModified() Assert.Empty(body); } - [Fact] - public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -326,7 +344,7 @@ public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert sendFileMock.Verify(); @@ -372,8 +390,11 @@ public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHtt Assert.Equal(contentLength, httpResponse.ContentLength); } - [Fact] - public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + string action, + Func function) { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; @@ -385,7 +406,7 @@ public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert Assert.Equal(expectedContentType, httpContext.Response.ContentType); @@ -395,8 +416,11 @@ public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() Assert.Equal(CancellationToken.None, sendFile.Token); } - [Fact] - public async Task ExecuteResultAsync_WorksWithAbsolutePaths() + [Theory] + [MemberData(nameof(GetActions))] + public async Task ExecuteResultAsync_WorksWithAbsolutePaths( + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine(".", "TestFiles", "FilePathResultTestFile.txt")); @@ -409,7 +433,7 @@ public async Task ExecuteResultAsync_WorksWithAbsolutePaths() var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(context); + await function(result, action == "ActionContext" ? context : httpContext); // Assert Assert.Equal(Path.GetFullPath(Path.Combine(".", "TestFiles", "FilePathResultTestFile.txt")), sendFile.Name); @@ -477,7 +501,16 @@ public void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(st Assert.ThrowsAsync(() => result.ExecuteResultAsync(context)); } - private class TestPhysicalFileResult : PhysicalFileResult + public static IEnumerable GetActions() + { + return new List + { + new object[] { "ActionContext", new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)) }, + new object[] { "HttpContext", new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)) }, + }; + } + + private class TestPhysicalFileResult : PhysicalFileResult, IResult { public TestPhysicalFileResult(string filePath, string contentType) : base(filePath, contentType) @@ -489,6 +522,13 @@ public override Task ExecuteResultAsync(ActionContext context) var executor = context.HttpContext.RequestServices.GetRequiredService(); return executor.ExecuteAsync(context, this); } + + Task IResult.ExecuteAsync(HttpContext httpContext) + { + var lastModified = DateTimeOffset.MinValue.AddDays(1); + var fileLastModified = new DateTimeOffset(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, TimeSpan.FromSeconds(0)); + return ExecuteAsyncInternal(httpContext, this, fileLastModified, 34); + } } private class TestPhysicalFileResultExecutor : PhysicalFileResultExecutor @@ -564,4 +604,4 @@ private static HttpContext GetHttpContext() return httpContext; } } -} \ No newline at end of file +} From c5c8ec6537fb7cf702b19bf1e1ebb57241b18b37 Mon Sep 17 00:00:00 2001 From: Juan Barahona Date: Tue, 18 May 2021 21:28:33 -0400 Subject: [PATCH 3/5] Revert FileStreamResult as is not completed --- src/Mvc/Mvc.Core/src/FileStreamResult.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Mvc/Mvc.Core/src/FileStreamResult.cs b/src/Mvc/Mvc.Core/src/FileStreamResult.cs index 3fb885fa3d17..ba358eeb09c4 100644 --- a/src/Mvc/Mvc.Core/src/FileStreamResult.cs +++ b/src/Mvc/Mvc.Core/src/FileStreamResult.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -16,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc /// Represents an that when executed will /// write a file from a stream to the response. /// - public class FileStreamResult : FileResult, IResult + public class FileStreamResult : FileResult { private Stream _fileStream; @@ -80,10 +79,5 @@ public override Task ExecuteResultAsync(ActionContext context) var executor = context.HttpContext.RequestServices.GetRequiredService>(); return executor.ExecuteAsync(context, this); } - - Task IResult.ExecuteAsync(HttpContext httpContext) - { - throw new NotImplementedException(); - } } } From b5d74c971d6b8f40ffbfb4cc40d492f3a95bfc68 Mon Sep 17 00:00:00 2001 From: Juan Barahona Date: Fri, 21 May 2021 00:24:49 -0400 Subject: [PATCH 4/5] Adding existing test for new implementation of IResult --- ...ltTest.cs => BaseFileContentResultTest.cs} | 128 +-- ...tTest.cs => BasePhysicalFileResultTest.cs} | 171 ++-- .../Mvc.Core/test/BaseRedirectResultTest.cs | 90 ++ .../test/BaseVirtualFileResultTest.cs | 748 ++++++++++++++++ .../test/FileContentActionResultTest.cs | 167 ++++ src/Mvc/Mvc.Core/test/FileContentResult.cs | 115 +++ .../test/PhysicalFileActionResultTest.cs | 228 +++++ src/Mvc/Mvc.Core/test/PhysicalFileResult.cs | 199 +++++ .../Mvc.Core/test/RedirectActionResultTest.cs | 98 +++ src/Mvc/Mvc.Core/test/RedirectResultTest.cs | 163 +--- .../test/VirtualFileActionResultTest .cs | 238 +++++ .../Mvc.Core/test/VirtualFileResultTest.cs | 817 +++--------------- 12 files changed, 2082 insertions(+), 1080 deletions(-) rename src/Mvc/Mvc.Core/test/{FileContentResultTest.cs => BaseFileContentResultTest.cs} (81%) rename src/Mvc/Mvc.Core/test/{PhysicalFileResultTest.cs => BasePhysicalFileResultTest.cs} (80%) create mode 100644 src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs create mode 100644 src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs create mode 100644 src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs create mode 100644 src/Mvc/Mvc.Core/test/FileContentResult.cs create mode 100644 src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs create mode 100644 src/Mvc/Mvc.Core/test/PhysicalFileResult.cs create mode 100644 src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs create mode 100644 src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs diff --git a/src/Mvc/Mvc.Core/test/FileContentResultTest.cs b/src/Mvc/Mvc.Core/test/BaseFileContentResultTest.cs similarity index 81% rename from src/Mvc/Mvc.Core/test/FileContentResultTest.cs rename to src/Mvc/Mvc.Core/test/BaseFileContentResultTest.cs index 966e72db81e4..1ce224f8246a 100644 --- a/src/Mvc/Mvc.Core/test/FileContentResultTest.cs +++ b/src/Mvc/Mvc.Core/test/BaseFileContentResultTest.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; @@ -18,63 +17,9 @@ namespace Microsoft.AspNetCore.Mvc { - public class FileContentResultTest + public class BaseFileContentResultTest { - [Fact] - public void Constructor_SetsFileContents() - { - // Arrange - var fileContents = new byte[0]; - - // Act - var result = new FileContentResult(fileContents, "text/plain"); - - // Assert - Assert.Same(fileContents, result.FileContents); - } - - [Fact] - public void Constructor_SetsContentTypeAndParameters() - { - // Arrange - var fileContents = new byte[0]; - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var expectedMediaType = contentType; - - // Act - var result = new FileContentResult(fileContents, contentType); - - // Assert - Assert.Same(fileContents, result.FileContents); - MediaTypeAssert.Equal(expectedMediaType, result.ContentType); - } - - [Fact] - public void Constructor_SetsLastModifiedAndEtag() - { - // Arrange - var fileContents = new byte[0]; - var contentType = "text/plain"; - var expectedMediaType = contentType; - var lastModified = new DateTimeOffset(); - var entityTag = new EntityTagHeaderValue("\"Etag\""); - - // Act - var result = new FileContentResult(fileContents, contentType) - { - LastModified = lastModified, - EntityTag = entityTag - }; - - // Assert - Assert.Equal(lastModified, result.LastModified); - Assert.Equal(entityTag, result.EntityTag); - MediaTypeAssert.Equal(expectedMediaType, result.ContentType); - } - - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_CopiesBuffer_ToOutputStream( + public static async Task WriteFileAsync_CopiesBuffer_ToOutputStream( string action, Func function) { @@ -97,12 +42,13 @@ public async Task WriteFileAsync_CopiesBuffer_ToOutputStream( Assert.Equal(buffer, outStream.ToArray()); } - [Theory] - [InlineData(0, 4, "Hello", 5)] - [InlineData(6, 10, "World", 5)] - [InlineData(null, 5, "World", 5)] - [InlineData(6, null, "World", 5)] - public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + public static async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested( + long? start, + long? end, + string expectedString, + long contentLength, + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -129,7 +75,7 @@ public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeReque var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert start = start ?? 11 - end; @@ -148,9 +94,7 @@ public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeReque Assert.Equal(expectedString, body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( + public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( string action, Func function) { @@ -207,9 +151,7 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( } } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored( + public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored( string action, Func function) { @@ -251,9 +193,7 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored( Assert.Equal("Hello World", body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored( + public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored( string action, Func function) { @@ -296,11 +236,10 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored( Assert.Equal("Hello World", body); } - [Theory] - [InlineData("0-5")] - [InlineData("bytes = ")] - [InlineData("bytes = 1-4, 5-11")] - public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(string rangeString) + public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored( + string rangeString, + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -322,7 +261,7 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnore var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -336,10 +275,10 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnore Assert.Equal("Hello World", body); } - [Theory] - [InlineData("bytes = 12-13")] - [InlineData("bytes = -0")] - public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString) + public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable( + string rangeString, + string action, + Func function) { // Arrange var contentType = "text/plain"; @@ -361,7 +300,7 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotS var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -378,9 +317,7 @@ public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotS Assert.Empty(body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored( + public static async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored( string action, Func function) { @@ -423,9 +360,7 @@ public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored( Assert.Empty(body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_NotModified_RangeRequestedIgnored( + public static async Task WriteFileAsync_NotModified_RangeRequestedIgnored( string action, Func function) { @@ -469,9 +404,7 @@ public async Task WriteFileAsync_NotModified_RangeRequestedIgnored( Assert.Empty(body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( string action, Func function) { @@ -496,15 +429,6 @@ public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( Assert.Equal(expectedContentType, httpContext.Response.ContentType); } - public static IEnumerable GetActions() - { - return new List - { - new object[] { "ActionContext", new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)) }, - new object[] { "HttpContext", new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)) }, - }; - } - private static IServiceCollection CreateServices() { var services = new ServiceCollection(); diff --git a/src/Mvc/Mvc.Core/test/PhysicalFileResultTest.cs b/src/Mvc/Mvc.Core/test/BasePhysicalFileResultTest.cs similarity index 80% rename from src/Mvc/Mvc.Core/test/PhysicalFileResultTest.cs rename to src/Mvc/Mvc.Core/test/BasePhysicalFileResultTest.cs index caa9635d97e6..331fac3d0c4c 100644 --- a/src/Mvc/Mvc.Core/test/PhysicalFileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/BasePhysicalFileResultTest.cs @@ -21,43 +21,15 @@ namespace Microsoft.AspNetCore.Mvc { - public class PhysicalFileResultTest + public class BasePhysicalFileResultTest { - [Fact] - public void Constructor_SetsFileName() - { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - - // Act - var result = new TestPhysicalFileResult(path, "text/plain"); - - // Assert - Assert.Equal(path, result.FileName); - } - - [Fact] - public void Constructor_SetsContentTypeAndParameters() - { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var expectedMediaType = contentType; - - // Act - var result = new TestPhysicalFileResult(path, contentType); - - // Assert - Assert.Equal(path, result.FileName); - MediaTypeAssert.Equal(expectedMediaType, result.ContentType); - } - - [Theory] - [InlineData(0, 3, "File", 4)] - [InlineData(8, 13, "Result", 6)] - [InlineData(null, 5, "ts�", 5)] - [InlineData(8, null, "ResultTestFile contents�", 26)] - public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + public static async Task WriteFileAsync_WritesRangeRequested( + long? start, + long? end, + string expectedString, + long contentLength, + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -73,7 +45,7 @@ public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, st var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var startResult = start ?? 34 - end; @@ -90,9 +62,7 @@ public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, st Assert.Equal((long?)contentLength, sendFile.Length); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( + public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( string action, Func function) { @@ -128,9 +98,7 @@ public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( Assert.Equal(4, sendFile.Length); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( + public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( string action, Func function) { @@ -160,9 +128,7 @@ public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored Assert.Null(sendFile.Length); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( + public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( string action, Func function) { @@ -193,11 +159,10 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( Assert.Null(sendFile.Length); } - [Theory] - [InlineData("0-5")] - [InlineData("bytes = ")] - [InlineData("bytes = 1-4, 5-11")] - public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) + public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored( + string rangeString, + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -212,7 +177,7 @@ public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -224,10 +189,10 @@ public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string Assert.Null(sendFile.Length); } - [Theory] - [InlineData("bytes = 35-36")] - [InlineData("bytes = -0")] - public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) + public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( + string rangeString, + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -242,7 +207,7 @@ public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -258,9 +223,7 @@ public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString Assert.Empty(body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_RangeRequested_PreconditionFailed( + public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( string action, Func function) { @@ -291,9 +254,7 @@ public async Task WriteFileAsync_RangeRequested_PreconditionFailed( Assert.Empty(body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_RangeRequested_NotModified( + public static async Task WriteFileAsync_RangeRequested_NotModified( string action, Func function) { @@ -325,9 +286,7 @@ public async Task WriteFileAsync_RangeRequested_NotModified( Assert.Empty(body); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( + public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( string action, Func function) { @@ -350,12 +309,12 @@ public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( sendFileMock.Verify(); } - [Theory] - [InlineData(0, 3, 4)] - [InlineData(8, 13, 6)] - [InlineData(null, 3, 3)] - [InlineData(8, null, 26)] - public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, long contentLength) + public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + long? start, + long? end, + long contentLength, + string action, + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -372,7 +331,7 @@ public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHtt var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await result.ExecuteResultAsync(actionContext); + await function(result, action == "ActionContext" ? actionContext : httpContext); // Assert start = start ?? 34 - end; @@ -390,9 +349,7 @@ public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHtt Assert.Equal(contentLength, httpResponse.ContentLength); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( string action, Func function) { @@ -416,9 +373,7 @@ public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( Assert.Equal(CancellationToken.None, sendFile.Token); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_WorksWithAbsolutePaths( + public static async Task ExecuteResultAsync_WorksWithAbsolutePaths( string action, Func function) { @@ -442,20 +397,10 @@ public async Task ExecuteResultAsync_WorksWithAbsolutePaths( Assert.Equal(CancellationToken.None, sendFile.Token); } - [Theory] - [InlineData("FilePathResultTestFile.txt")] - [InlineData("./FilePathResultTestFile.txt")] - [InlineData(".\\FilePathResultTestFile.txt")] - [InlineData("~/FilePathResultTestFile.txt")] - [InlineData("..\\TestFiles/FilePathResultTestFile.txt")] - [InlineData("..\\TestFiles\\FilePathResultTestFile.txt")] - [InlineData("..\\TestFiles/SubFolder/SubFolderTestFile.txt")] - [InlineData("..\\TestFiles\\SubFolder\\SubFolderTestFile.txt")] - [InlineData("..\\TestFiles/SubFolder\\SubFolderTestFile.txt")] - [InlineData("..\\TestFiles\\SubFolder/SubFolderTestFile.txt")] - [InlineData("~/SubFolder/SubFolderTestFile.txt")] - [InlineData("~/SubFolder\\SubFolderTestFile.txt")] - public async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(string path) + public static async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths( + string path, + string action, + Func function) { // Arrange var result = new TestPhysicalFileResult(path, "text/plain"); @@ -463,51 +408,39 @@ public async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(string path) var expectedMessage = $"Path '{path}' was not rooted."; // Act - var ex = await Assert.ThrowsAsync(() => result.ExecuteResultAsync(context)); + var ex = await Assert.ThrowsAsync( + () => function(result, action == "ActionContext" ? context : context.HttpContext)); // Assert Assert.Equal(expectedMessage, ex.Message); } - [Theory] - [InlineData("/SubFolder/SubFolderTestFile.txt")] - [InlineData("\\SubFolder\\SubFolderTestFile.txt")] - [InlineData("/SubFolder\\SubFolderTestFile.txt")] - [InlineData("\\SubFolder/SubFolderTestFile.txt")] - [InlineData("./SubFolder/SubFolderTestFile.txt")] - [InlineData(".\\SubFolder\\SubFolderTestFile.txt")] - [InlineData("./SubFolder\\SubFolderTestFile.txt")] - [InlineData(".\\SubFolder/SubFolderTestFile.txt")] - public void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(string path) + public static void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths( + string path, + string action, + Func function) { // Arrange var result = new TestPhysicalFileResult(path, "text/plain"); var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); // Act & Assert - Assert.ThrowsAsync(() => result.ExecuteResultAsync(context)); + Assert.ThrowsAsync( + () => function(result, action == "ActionContext" ? context : context.HttpContext)); } - [Theory] - [InlineData("/FilePathResultTestFile.txt")] - [InlineData("\\FilePathResultTestFile.txt")] - public void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(string path) + public static void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths( + string path, + string action, + Func function) { // Arrange var result = new TestPhysicalFileResult(path, "text/plain"); var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); // Act & Assert - Assert.ThrowsAsync(() => result.ExecuteResultAsync(context)); - } - - public static IEnumerable GetActions() - { - return new List - { - new object[] { "ActionContext", new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)) }, - new object[] { "HttpContext", new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)) }, - }; + Assert.ThrowsAsync( + () => function(result, action == "ActionContext" ? context : context.HttpContext)); } private class TestPhysicalFileResult : PhysicalFileResult, IResult diff --git a/src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs b/src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs new file mode 100644 index 000000000000..733b93715e0a --- /dev/null +++ b/src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs @@ -0,0 +1,90 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class BaseRedirectResultTest + { + public static async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( + string appRoot, + string contentPath, + string expectedPath, + string action, + Func function) + { + // Arrange + var httpContext = GetHttpContext(appRoot); + var actionContext = GetActionContext(httpContext); + var result = new RedirectResult(contentPath); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + // Verifying if Redirect was called with the specific Url and parameter flag. + Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); + Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); + } + + public static async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( + string appRoot, + string contentPath, + string expectedPath, + string action, + Func function) + { + // Arrange + var httpContext = GetHttpContext(appRoot); + var actionContext = GetActionContext(httpContext); + var result = new RedirectResult(contentPath); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + // Verifying if Redirect was called with the specific Url and parameter flag. + Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); + Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); + } + + private static ActionContext GetActionContext(HttpContext httpContext) + { + var routeData = new RouteData(); + routeData.Routers.Add(new Mock().Object); + + return new ActionContext(httpContext, + routeData, + new ActionDescriptor()); + } + + private static IServiceProvider GetServiceProvider() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton, RedirectResultExecutor>(); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); + return serviceCollection.BuildServiceProvider(); + } + + private static HttpContext GetHttpContext( + string appRoot) + { + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = GetServiceProvider(); + httpContext.Request.PathBase = new PathString(appRoot); + return httpContext; + } + } +} diff --git a/src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs b/src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs new file mode 100644 index 000000000000..ae9e4d37f370 --- /dev/null +++ b/src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs @@ -0,0 +1,748 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.IO.Pipelines; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Net.Http.Headers; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class BaseVirtualFileResultTest + { + public static async Task WriteFileAsync_WritesRangeRequested( + long? start, + long? end, + string expectedString, + long contentLength, + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + result.EnableRangeProcessing = true; + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var requestHeaders = httpContext.Request.GetTypedHeaders(); + requestHeaders.Range = new RangeHeaderValue(start, end); + requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var startResult = start ?? 33 - end; + var endResult = startResult + contentLength - 1; + var httpResponse = actionContext.HttpContext.Response; + var contentRange = new ContentRangeHeaderValue(startResult.Value, endResult.Value, 33); + Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); + Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); + Assert.NotEmpty(httpResponse.Headers.LastModified); + Assert.Equal(contentLength, httpResponse.ContentLength); + Assert.Equal(path, sendFileFeature.Name); + Assert.Equal(startResult, sendFileFeature.Offset); + Assert.Equal((long?)contentLength, sendFileFeature.Length); + } + + public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + result.EnableRangeProcessing = true; + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); + var requestHeaders = httpContext.Request.GetTypedHeaders(); + requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; + requestHeaders.Range = new RangeHeaderValue(0, 3); + requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var httpResponse = actionContext.HttpContext.Response; + Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); + var contentRange = new ContentRangeHeaderValue(0, 3, 33); + Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); + Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); + Assert.Equal(4, httpResponse.ContentLength); + Assert.Equal(path, sendFileFeature.Name); + Assert.Equal(0, sendFileFeature.Offset); + Assert.Equal(4, sendFileFeature.Length); + } + + public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); + var requestHeaders = httpContext.Request.GetTypedHeaders(); + requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; + requestHeaders.Range = new RangeHeaderValue(0, 3); + requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var httpResponse = actionContext.HttpContext.Response; + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); + Assert.Equal(path, sendFileFeature.Name); + Assert.Equal(0, sendFileFeature.Offset); + Assert.Null(sendFileFeature.Length); + } + + public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + result.EnableRangeProcessing = true; + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); + var requestHeaders = httpContext.Request.GetTypedHeaders(); + requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; + requestHeaders.Range = new RangeHeaderValue(0, 3); + requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"NotEtag\"")); + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var httpResponse = actionContext.HttpContext.Response; + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); + Assert.Equal(path, sendFileFeature.Name); + Assert.Equal(0, sendFileFeature.Offset); + Assert.Null(sendFileFeature.Length); + } + + public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored( + string rangeString, + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + result.EnableRangeProcessing = true; + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var requestHeaders = httpContext.Request.GetTypedHeaders(); + httpContext.Request.Headers.Range = rangeString; + requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var httpResponse = actionContext.HttpContext.Response; + Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); + Assert.Empty(httpResponse.Headers.ContentRange); + Assert.NotEmpty(httpResponse.Headers.LastModified); + Assert.Equal(path, sendFileFeature.Name); + Assert.Equal(0, sendFileFeature.Offset); + Assert.Null(sendFileFeature.Length); + } + + public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( + string rangeString, + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + result.EnableRangeProcessing = true; + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var httpContext = GetHttpContext(); + httpContext.Response.Body = new MemoryStream(); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var requestHeaders = httpContext.Request.GetTypedHeaders(); + httpContext.Request.Headers.Range = rangeString; + requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); + httpContext.Request.Method = HttpMethods.Get; + httpContext.Response.Body = new MemoryStream(); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var httpResponse = actionContext.HttpContext.Response; + httpResponse.Body.Seek(0, SeekOrigin.Begin); + var streamReader = new StreamReader(httpResponse.Body); + var body = streamReader.ReadToEndAsync().Result; + var contentRange = new ContentRangeHeaderValue(33); + Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); + Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); + Assert.NotEmpty(httpResponse.Headers.LastModified); + Assert.Equal(0, httpResponse.ContentLength); + Assert.Empty(body); + } + + public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + result.EnableRangeProcessing = true; + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var requestHeaders = httpContext.Request.GetTypedHeaders(); + requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue; + httpContext.Request.Headers.Range = "bytes = 0-6"; + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var httpResponse = actionContext.HttpContext.Response; + Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode); + Assert.Null(httpResponse.ContentLength); + Assert.Empty(httpResponse.Headers.ContentRange); + Assert.NotEmpty(httpResponse.Headers.LastModified); + Assert.Null(sendFileFeature.Name); // Not called + } + + public static async Task WriteFileAsync_RangeRequested_NotModified( + string action, + Func function) + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var result = new TestVirtualFileResult(path, contentType); + result.EnableRangeProcessing = true; + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var requestHeaders = httpContext.Request.GetTypedHeaders(); + requestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(1); + httpContext.Request.Headers.Range = "bytes = 0-6"; + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + var httpResponse = actionContext.HttpContext.Response; + Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode); + Assert.Null(httpResponse.ContentLength); + Assert.Empty(httpResponse.Headers.ContentRange); + Assert.NotEmpty(httpResponse.Headers.LastModified); + Assert.False(httpResponse.Headers.ContainsKey(HeaderNames.ContentType)); + Assert.Null(sendFileFeature.Name); // Not called + } + + public static async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent( + string action, + Func function) + { + // Arrange + var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); + var result = new TestVirtualFileResult(path, "text/plain"); + + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? context : httpContext); + + // Assert + Assert.Equal(path, sendFileFeature.Name); + Assert.Equal(0, sendFileFeature.Offset); + Assert.Null(sendFileFeature.Length); + } + + public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( + string action, + Func function) + { + // Arrange + var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); + var result = new TestVirtualFileResult(path, "text/plain") + { + FileProvider = GetFileProvider(path), + }; + + var sendFileMock = new Mock(); + sendFileMock + .Setup(s => s.SendFileAsync(path, 0, null, CancellationToken.None)) + .Returns(Task.FromResult(0)); + + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileMock.Object); + var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? context : httpContext); + + // Assert + sendFileMock.Verify(); + } + public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + long? start, + long? end, + string expectedString, + long contentLength, + string action, + Func function) + { + // Arrange + var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); + var result = new TestVirtualFileResult(path, "text/plain") + { + FileProvider = GetFileProvider(path), + EnableRangeProcessing = true, + }; + + var sendFile = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFile); + var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var appEnvironment = new Mock(); + appEnvironment.Setup(app => app.WebRootFileProvider) + .Returns(GetFileProvider(path)); + httpContext.RequestServices = new ServiceCollection() + .AddSingleton(appEnvironment.Object) + .AddTransient, TestVirtualFileResultExecutor>() + .AddTransient() + .BuildServiceProvider(); + + var requestHeaders = httpContext.Request.GetTypedHeaders(); + requestHeaders.Range = new RangeHeaderValue(start, end); + requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); + httpContext.Request.Method = HttpMethods.Get; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? actionContext : httpContext); + + // Assert + start = start ?? 33 - end; + end = start + contentLength - 1; + var httpResponse = actionContext.HttpContext.Response; + Assert.Equal(Path.Combine("TestFiles", "FilePathResultTestFile.txt"), sendFile.Name); + Assert.Equal(start, sendFile.Offset); + Assert.Equal(contentLength, sendFile.Length); + Assert.Equal(CancellationToken.None, sendFile.Token); + var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, 33); + Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); + Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); + Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); + Assert.NotEmpty(httpResponse.Headers.LastModified); + Assert.Equal(contentLength, httpResponse.ContentLength); + } + + public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + string action, + Func function) + { + // Arrange + var expectedContentType = "text/foo; charset=us-ascii"; + var result = new TestVirtualFileResult( + "FilePathResultTestFile_ASCII.txt", expectedContentType) + { + FileProvider = GetFileProvider("FilePathResultTestFile_ASCII.txt"), + }; + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? context : httpContext); + + // Assert + Assert.Equal(expectedContentType, httpContext.Response.ContentType); + Assert.Equal("FilePathResultTestFile_ASCII.txt", sendFileFeature.Name); + } + + public static async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths( + string action, + Func function) + { + // Arrange + var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); + var result = new TestVirtualFileResult(path, "text/plain") + { + FileProvider = GetFileProvider(path), + }; + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? context : httpContext); + + // Assert + Assert.Equal(path, sendFileFeature.Name); + } + + public static async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths( + string path, + string action, + Func function) + { + // Arrange + var result = new TestVirtualFileResult(path, "text/plain") + { + FileProvider = GetFileProvider(path), + }; + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + + var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? context : httpContext); + + // Assert + Mock.Get(result.FileProvider).Verify(); + Assert.Equal(path, sendFileFeature.Name); + } + + public static async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider( + string path, + string action, + Func function) + { + // Arrange + var expectedPath = path.Substring(1); + var result = new TestVirtualFileResult(path, "text/plain") + { + FileProvider = GetFileProvider(expectedPath), + }; + + var sendFileFeature = new TestSendFileFeature(); + var httpContext = GetHttpContext(); + httpContext.Features.Set(sendFileFeature); + + var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + + // Act + await function(result, action == "ActionContext" ? context : httpContext); + + // Assert + Mock.Get(result.FileProvider).Verify(); + Assert.Equal(expectedPath, sendFileFeature.Name); + } + + public static async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles( + string action, + Func function) + { + // Arrange + var httpContext = GetHttpContext(typeof(VirtualFileResultExecutor)); + httpContext.Response.Body = new MemoryStream(); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var expectedData = "This is an embedded resource"; + var sourceStream = new MemoryStream(Encoding.UTF8.GetBytes(expectedData)); + + var nonDiskFileInfo = new Mock(); + nonDiskFileInfo.SetupGet(fi => fi.Exists).Returns(true); + nonDiskFileInfo.SetupGet(fi => fi.PhysicalPath).Returns(() => null); // set null to indicate non-disk file + nonDiskFileInfo.Setup(fi => fi.CreateReadStream()).Returns(sourceStream); + var nonDiskFileProvider = new Mock(); + nonDiskFileProvider.Setup(fp => fp.GetFileInfo(It.IsAny())).Returns(nonDiskFileInfo.Object); + + var filePathResult = new VirtualFileResult("/SampleEmbeddedFile.txt", "text/plain") + { + FileProvider = nonDiskFileProvider.Object + }; + + // Act + await function(filePathResult, action == "ActionContext" ? actionContext : httpContext); + + // Assert + httpContext.Response.Body.Position = 0; + var contents = await new StreamReader(httpContext.Response.Body).ReadToEndAsync(); + Assert.Equal(expectedData, contents); + } + + public static async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile( + string action, + Func function) + { + // Arrange + var path = "TestPath.txt"; + var fileInfo = new Mock(); + fileInfo.SetupGet(f => f.Exists).Returns(false); + var fileProvider = new Mock(); + fileProvider.Setup(f => f.GetFileInfo(path)).Returns(fileInfo.Object); + var filePathResult = new TestVirtualFileResult(path, "text/plain") + { + FileProvider = fileProvider.Object, + }; + + var expectedMessage = "Could not find file: " + path; + var context = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); + + // Act + var ex = await Assert.ThrowsAsync(() => function(filePathResult, action == "ActionContext" ? context : context.HttpContext)); + + // Assert + Assert.Equal(expectedMessage, ex.Message); + Assert.Equal(path, ex.FileName); + } + + private static IServiceCollection CreateServices(Type executorType) + { + var services = new ServiceCollection(); + + var hostingEnvironment = new Mock(); + + services.AddSingleton, TestVirtualFileResultExecutor>(); + if (executorType != null) + { + services.AddSingleton(typeof(IActionResultExecutor), executorType); + } + + services.AddSingleton(hostingEnvironment.Object); + services.AddSingleton(NullLoggerFactory.Instance); + + return services; + } + + private static HttpContext GetHttpContext(Type executorType = null) + { + var services = CreateServices(executorType); + + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = services.BuildServiceProvider(); + + return httpContext; + } + + private static IFileProvider GetFileProvider(string path) + { + var fileInfo = new Mock(); + fileInfo.SetupGet(fi => fi.Length).Returns(33); + fileInfo.SetupGet(fi => fi.Exists).Returns(true); + var lastModified = DateTimeOffset.MinValue.AddDays(1); + lastModified = new DateTimeOffset(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, TimeSpan.FromSeconds(0)); + fileInfo.SetupGet(fi => fi.LastModified).Returns(lastModified); + fileInfo.SetupGet(fi => fi.PhysicalPath).Returns(path); + var fileProvider = new Mock(); + fileProvider.Setup(fp => fp.GetFileInfo(path)) + .Returns(fileInfo.Object) + .Verifiable(); + + return fileProvider.Object; + } + + private class TestVirtualFileResult : VirtualFileResult + { + public TestVirtualFileResult(string filePath, string contentType) + : base(filePath, contentType) + { + } + + public override Task ExecuteResultAsync(ActionContext context) + { + var executor = (TestVirtualFileResultExecutor)context.HttpContext.RequestServices.GetRequiredService>(); + return executor.ExecuteAsync(context, this); + } + } + + private class TestVirtualFileResultExecutor : VirtualFileResultExecutor + { + public TestVirtualFileResultExecutor(ILoggerFactory loggerFactory, IWebHostEnvironment hostingEnvironment) + : base(loggerFactory, hostingEnvironment) + { + } + } + + private class TestSendFileFeature : IHttpResponseBodyFeature + { + public string Name { get; set; } + public long Offset { get; set; } + public long? Length { get; set; } + public CancellationToken Token { get; set; } + + public Stream Stream => throw new NotImplementedException(); + + public PipeWriter Writer => throw new NotImplementedException(); + + public Task CompleteAsync() + { + throw new NotImplementedException(); + } + + public void DisableBuffering() + { + throw new NotImplementedException(); + } + + public Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) + { + Name = path; + Offset = offset; + Length = length; + Token = cancellation; + + return Task.FromResult(0); + } + + public Task StartAsync(CancellationToken cancellation = default) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs b/src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs new file mode 100644 index 000000000000..958a665b3908 --- /dev/null +++ b/src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs @@ -0,0 +1,167 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class FileContentActionResultTest + { + [Fact] + public void Constructor_SetsFileContents() + { + // Arrange + var fileContents = new byte[0]; + + // Act + var result = new FileContentResult(fileContents, "text/plain"); + + // Assert + Assert.Same(fileContents, result.FileContents); + } + + [Fact] + public void Constructor_SetsContentTypeAndParameters() + { + // Arrange + var fileContents = new byte[0]; + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var expectedMediaType = contentType; + + // Act + var result = new FileContentResult(fileContents, contentType); + + // Assert + Assert.Same(fileContents, result.FileContents); + MediaTypeAssert.Equal(expectedMediaType, result.ContentType); + } + + [Fact] + public void Constructor_SetsLastModifiedAndEtag() + { + // Arrange + var fileContents = new byte[0]; + var contentType = "text/plain"; + var expectedMediaType = contentType; + var lastModified = new DateTimeOffset(); + var entityTag = new EntityTagHeaderValue("\"Etag\""); + + // Act + var result = new FileContentResult(fileContents, contentType) + { + LastModified = lastModified, + EntityTag = entityTag + }; + + // Assert + Assert.Equal(lastModified, result.LastModified); + Assert.Equal(entityTag, result.EntityTag); + MediaTypeAssert.Equal(expectedMediaType, result.ContentType); + } + + [Fact] + public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_CopiesBuffer_ToOutputStream(actionType, action); + } + + [Theory] + [InlineData(0, 4, "Hello", 5)] + [InlineData(6, 10, "World", 5)] + [InlineData(null, 5, "World", 5)] + [InlineData(6, null, "World", 5)] + public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest + .WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(start, end, expectedString, contentLength, actionType, action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored(actionType, action); + } + + [Theory] + [InlineData("0-5")] + [InlineData("bytes = ")] + [InlineData("bytes = 1-4, 5-11")] + public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(string rangeString) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest + .WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(rangeString, actionType, action); + } + + [Theory] + [InlineData("bytes = 12-13")] + [InlineData("bytes = -0")] + public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest + .WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(rangeString, actionType, action); + } + + [Fact] + public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_PreconditionFailed_RangeRequestedIgnored(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_NotModified_RangeRequestedIgnored(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseFileContentResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + } + } +} diff --git a/src/Mvc/Mvc.Core/test/FileContentResult.cs b/src/Mvc/Mvc.Core/test/FileContentResult.cs new file mode 100644 index 000000000000..32f5e2ea2e2b --- /dev/null +++ b/src/Mvc/Mvc.Core/test/FileContentResult.cs @@ -0,0 +1,115 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class FileContentResultTest + { + [Fact] + public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_CopiesBuffer_ToOutputStream(actionType, action); + } + + [Theory] + [InlineData(0, 4, "Hello", 5)] + [InlineData(6, 10, "World", 5)] + [InlineData(null, 5, "World", 5)] + [InlineData(6, null, "World", 5)] + public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest + .WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(start, end, expectedString, contentLength, actionType, action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored(actionType, action); + } + + [Theory] + [InlineData("0-5")] + [InlineData("bytes = ")] + [InlineData("bytes = 1-4, 5-11")] + public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(string rangeString) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest + .WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(rangeString, actionType, action); + } + + [Theory] + [InlineData("bytes = 12-13")] + [InlineData("bytes = -0")] + public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest + .WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(rangeString, actionType, action); + } + + [Fact] + public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_PreconditionFailed_RangeRequestedIgnored(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest.WriteFileAsync_NotModified_RangeRequestedIgnored(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseFileContentResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + } + } +} diff --git a/src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs b/src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs new file mode 100644 index 000000000000..654c656ec9a3 --- /dev/null +++ b/src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs @@ -0,0 +1,228 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class PhysicalFileActionResultTest + { + [Fact] + public void Constructor_SetsFileName() + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + + // Act + var result = new PhysicalFileResult(path, "text/plain"); + + // Assert + Assert.Equal(path, result.FileName); + } + + [Fact] + public void Constructor_SetsContentTypeAndParameters() + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var expectedMediaType = contentType; + + // Act + var result = new PhysicalFileResult(path, contentType); + + // Assert + Assert.Equal(path, result.FileName); + MediaTypeAssert.Equal(expectedMediaType, result.ContentType); + } + + [Theory] + [InlineData(0, 3, "File", 4)] + [InlineData(8, 13, "Result", 6)] + [InlineData(null, 5, "ts�", 5)] + [InlineData(8, null, "ResultTestFile contents�", 26)] + public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_WritesRangeRequested( + start, + end, + expectedString, + contentLength, + actionType, + action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); + } + + [Theory] + [InlineData("0-5")] + [InlineData("bytes = ")] + [InlineData("bytes = 1-4, 5-11")] + public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest + .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); + } + + [Theory] + [InlineData("bytes = 35-36")] + [InlineData("bytes = -0")] + public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest + .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeRequested_PreconditionFailed() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeRequested_NotModified() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); + } + + [Theory] + [InlineData(0, 3, 4)] + [InlineData(8, 13, 6)] + [InlineData(null, 3, 3)] + [InlineData(8, null, 26)] + public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, long contentLength) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + start, + end, + contentLength, + actionType, + action); + } + + [Fact] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_WorksWithAbsolutePaths() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_WorksWithAbsolutePaths(actionType, action); + } + + [Theory] + [InlineData("FilePathResultTestFile.txt")] + [InlineData("./FilePathResultTestFile.txt")] + [InlineData(".\\FilePathResultTestFile.txt")] + [InlineData("~/FilePathResultTestFile.txt")] + [InlineData("..\\TestFiles/FilePathResultTestFile.txt")] + [InlineData("..\\TestFiles\\FilePathResultTestFile.txt")] + [InlineData("..\\TestFiles/SubFolder/SubFolderTestFile.txt")] + [InlineData("..\\TestFiles\\SubFolder\\SubFolderTestFile.txt")] + [InlineData("..\\TestFiles/SubFolder\\SubFolderTestFile.txt")] + [InlineData("..\\TestFiles\\SubFolder/SubFolderTestFile.txt")] + [InlineData("~/SubFolder/SubFolderTestFile.txt")] + [InlineData("~/SubFolder\\SubFolderTestFile.txt")] + public async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(string path) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BasePhysicalFileResultTest + .ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(path, actionType, action); + } + + [Theory] + [InlineData("/SubFolder/SubFolderTestFile.txt")] + [InlineData("\\SubFolder\\SubFolderTestFile.txt")] + [InlineData("/SubFolder\\SubFolderTestFile.txt")] + [InlineData("\\SubFolder/SubFolderTestFile.txt")] + [InlineData("./SubFolder/SubFolderTestFile.txt")] + [InlineData(".\\SubFolder\\SubFolderTestFile.txt")] + [InlineData("./SubFolder\\SubFolderTestFile.txt")] + [InlineData(".\\SubFolder/SubFolderTestFile.txt")] + public void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(string path) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + BasePhysicalFileResultTest + .ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(path, actionType, action); + } + + [Theory] + [InlineData("/FilePathResultTestFile.txt")] + [InlineData("\\FilePathResultTestFile.txt")] + public void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(string path) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + BasePhysicalFileResultTest + .ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(path, actionType, action); + } + } +} diff --git a/src/Mvc/Mvc.Core/test/PhysicalFileResult.cs b/src/Mvc/Mvc.Core/test/PhysicalFileResult.cs new file mode 100644 index 000000000000..ddc67627bae6 --- /dev/null +++ b/src/Mvc/Mvc.Core/test/PhysicalFileResult.cs @@ -0,0 +1,199 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class PhysicalFileResultTest + { + [Theory] + [InlineData(0, 3, "File", 4)] + [InlineData(8, 13, "Result", 6)] + [InlineData(null, 5, "ts�", 5)] + [InlineData(8, null, "ResultTestFile contents�", 26)] + public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_WritesRangeRequested( + start, + end, + expectedString, + contentLength, + actionType, + action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); + } + + [Theory] + [InlineData("0-5")] + [InlineData("bytes = ")] + [InlineData("bytes = 1-4, 5-11")] + public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest + .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); + } + + [Theory] + [InlineData("bytes = 35-36")] + [InlineData("bytes = -0")] + public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest + .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeRequested_PreconditionFailed() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeRequested_NotModified() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); + } + + [Theory] + [InlineData(0, 3, 4)] + [InlineData(8, 13, 6)] + [InlineData(null, 3, 3)] + [InlineData(8, null, 26)] + public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, long contentLength) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + start, + end, + contentLength, + actionType, + action); + } + + [Fact] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_WorksWithAbsolutePaths() + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest.ExecuteResultAsync_WorksWithAbsolutePaths(actionType, action); + } + + [Theory] + [InlineData("FilePathResultTestFile.txt")] + [InlineData("./FilePathResultTestFile.txt")] + [InlineData(".\\FilePathResultTestFile.txt")] + [InlineData("~/FilePathResultTestFile.txt")] + [InlineData("..\\TestFiles/FilePathResultTestFile.txt")] + [InlineData("..\\TestFiles\\FilePathResultTestFile.txt")] + [InlineData("..\\TestFiles/SubFolder/SubFolderTestFile.txt")] + [InlineData("..\\TestFiles\\SubFolder\\SubFolderTestFile.txt")] + [InlineData("..\\TestFiles/SubFolder\\SubFolderTestFile.txt")] + [InlineData("..\\TestFiles\\SubFolder/SubFolderTestFile.txt")] + [InlineData("~/SubFolder/SubFolderTestFile.txt")] + [InlineData("~/SubFolder\\SubFolderTestFile.txt")] + public async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(string path) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BasePhysicalFileResultTest + .ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(path, actionType, action); + } + + [Theory] + [InlineData("/SubFolder/SubFolderTestFile.txt")] + [InlineData("\\SubFolder\\SubFolderTestFile.txt")] + [InlineData("/SubFolder\\SubFolderTestFile.txt")] + [InlineData("\\SubFolder/SubFolderTestFile.txt")] + [InlineData("./SubFolder/SubFolderTestFile.txt")] + [InlineData(".\\SubFolder\\SubFolderTestFile.txt")] + [InlineData("./SubFolder\\SubFolderTestFile.txt")] + [InlineData(".\\SubFolder/SubFolderTestFile.txt")] + public void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(string path) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + BasePhysicalFileResultTest + .ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(path, actionType, action); + } + + [Theory] + [InlineData("/FilePathResultTestFile.txt")] + [InlineData("\\FilePathResultTestFile.txt")] + public void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(string path) + { + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + BasePhysicalFileResultTest + .ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(path, actionType, action); + } + } +} diff --git a/src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs b/src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs new file mode 100644 index 000000000000..fbaa5642626b --- /dev/null +++ b/src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs @@ -0,0 +1,98 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class RedirectActionResultTest + { + [Fact] + public void RedirectResult_Constructor_WithParameterUrl_SetsResultUrlAndNotPermanentOrPreserveMethod() + { + // Arrange + var url = "/test/url"; + + // Act + var result = new RedirectResult(url); + + // Assert + Assert.False(result.PreserveMethod); + Assert.False(result.Permanent); + Assert.Same(url, result.Url); + } + + [Fact] + public void RedirectResult_Constructor_WithParameterUrlAndPermanent_SetsResultUrlAndPermanentNotPreserveMethod() + { + // Arrange + var url = "/test/url"; + + // Act + var result = new RedirectResult(url, permanent: true); + + // Assert + Assert.False(result.PreserveMethod); + Assert.True(result.Permanent); + Assert.Same(url, result.Url); + } + + [Fact] + public void RedirectResult_Constructor_WithParameterUrlPermanentAndPreservesMethod_SetsResultUrlPermanentAndPreservesMethod() + { + // Arrange + var url = "/test/url"; + + // Act + var result = new RedirectResult(url, permanent: true, preserveMethod: true); + + // Assert + Assert.True(result.PreserveMethod); + Assert.True(result.Permanent); + Assert.Same(url, result.Url); + } + + [Theory] + [InlineData("", "/Home/About", "/Home/About")] + [InlineData("/myapproot", "/test", "/test")] + public async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( + string appRoot, + string contentPath, + string expectedPath) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseRedirectResultTest.Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( + appRoot, + contentPath, + expectedPath, + actionType, + action); + } + + [Theory] + [InlineData(null, "~/Home/About", "/Home/About")] + [InlineData("/", "~/Home/About", "/Home/About")] + [InlineData("/", "~/", "/")] + [InlineData("", "~/Home/About", "/Home/About")] + [InlineData("/myapproot", "~/", "/myapproot/")] + public async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( + string appRoot, + string contentPath, + string expectedPath) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseRedirectResultTest.Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( + appRoot, + contentPath, + expectedPath, + actionType, + action); + } + } +} diff --git a/src/Mvc/Mvc.Core/test/RedirectResultTest.cs b/src/Mvc/Mvc.Core/test/RedirectResultTest.cs index 06ec9cf8d87b..c32c51cf6780 100644 --- a/src/Mvc/Mvc.Core/test/RedirectResultTest.cs +++ b/src/Mvc/Mvc.Core/test/RedirectResultTest.cs @@ -4,64 +4,12 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Mvc.Routing; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; using Xunit; namespace Microsoft.AspNetCore.Mvc { public class RedirectResultTest { - [Fact] - public void RedirectResult_Constructor_WithParameterUrl_SetsResultUrlAndNotPermanentOrPreserveMethod() - { - // Arrange - var url = "/test/url"; - - // Act - var result = new RedirectResult(url); - - // Assert - Assert.False(result.PreserveMethod); - Assert.False(result.Permanent); - Assert.Same(url, result.Url); - } - - [Fact] - public void RedirectResult_Constructor_WithParameterUrlAndPermanent_SetsResultUrlAndPermanentNotPreserveMethod() - { - // Arrange - var url = "/test/url"; - - // Act - var result = new RedirectResult(url, permanent: true); - - // Assert - Assert.False(result.PreserveMethod); - Assert.True(result.Permanent); - Assert.Same(url, result.Url); - } - - [Fact] - public void RedirectResult_Constructor_WithParameterUrlPermanentAndPreservesMethod_SetsResultUrlPermanentAndPreservesMethod() - { - // Arrange - var url = "/test/url"; - - // Act - var result = new RedirectResult(url, permanent: true, preserveMethod: true); - - // Assert - Assert.True(result.PreserveMethod); - Assert.True(result.Permanent); - Assert.Same(url, result.Url); - } - [Theory] [InlineData("", "/Home/About", "/Home/About")] [InlineData("/myapproot", "/test", "/test")] @@ -70,18 +18,15 @@ public async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( string contentPath, string expectedPath) { - // Arrange - var httpContext = GetHttpContext(appRoot); - var actionContext = GetActionContext(httpContext); - var result = new RedirectResult(contentPath); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - // Act - await result.ExecuteResultAsync(actionContext); - - // Assert - // Verifying if Redirect was called with the specific Url and parameter flag. - Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); - Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); + await BaseRedirectResultTest.Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( + appRoot, + contentPath, + expectedPath, + actionType, + action); } [Theory] @@ -95,91 +40,15 @@ public async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( string contentPath, string expectedPath) { - // Arrange - var httpContext = GetHttpContext(appRoot); - var actionContext = GetActionContext(httpContext); - var result = new RedirectResult(contentPath); - - // Act - await result.ExecuteResultAsync(actionContext); - - // Assert - // Verifying if Redirect was called with the specific Url and parameter flag. - Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); - Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); - } - - [Theory] - [InlineData("", "/Home/About", "/Home/About")] - [InlineData("/myapproot", "/test", "/test")] - public async Task ResultExecute_ReturnsContentPath_WhenItDoesNotStartWithTilde( - string appRoot, - string contentPath, - string expectedPath) - { - // Arrange - var httpContext = GetHttpContext(appRoot); - IResult result = new RedirectResult(contentPath); - - // Act - await result.ExecuteAsync(httpContext); - - // Assert - // Verifying if Redirect was called with the specific Url and parameter flag. - Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); - Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); - } - - [Theory] - [InlineData(null, "~/Home/About", "/Home/About")] - [InlineData("/", "~/Home/About", "/Home/About")] - [InlineData("/", "~/", "/")] - [InlineData("", "~/Home/About", "/Home/About")] - [InlineData("/myapproot", "~/", "/myapproot/")] - public async Task ResultExecute_ReturnsAppRelativePath_WhenItStartsWithTilde( - string appRoot, - string contentPath, - string expectedPath) - { - // Arrange - var httpContext = GetHttpContext(appRoot); - IResult result = new RedirectResult(contentPath); - - // Act - await result.ExecuteAsync(httpContext); - - // Assert - // Verifying if Redirect was called with the specific Url and parameter flag. - Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString()); - Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); - } - - private static ActionContext GetActionContext(HttpContext httpContext) - { - var routeData = new RouteData(); - routeData.Routers.Add(new Mock().Object); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - return new ActionContext(httpContext, - routeData, - new ActionDescriptor()); - } - - private static IServiceProvider GetServiceProvider() - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton, RedirectResultExecutor>(); - serviceCollection.AddSingleton(); - serviceCollection.AddTransient(); - return serviceCollection.BuildServiceProvider(); - } - - private static HttpContext GetHttpContext( - string appRoot) - { - var httpContext = new DefaultHttpContext(); - httpContext.RequestServices = GetServiceProvider(); - httpContext.Request.PathBase = new PathString(appRoot); - return httpContext; + await BaseRedirectResultTest.Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( + appRoot, + contentPath, + expectedPath, + actionType, + action); } } } diff --git a/src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs b/src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs new file mode 100644 index 000000000000..5a6afc6c7656 --- /dev/null +++ b/src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs @@ -0,0 +1,238 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc +{ + public class VirtualFileActionResultTest + { + [Fact] + public void Constructor_SetsFileName() + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + + // Act + var result = new VirtualFileResult(path, "text/plain"); + + // Assert + Assert.Equal(path, result.FileName); + } + + [Fact] + public void Constructor_SetsContentTypeAndParameters() + { + // Arrange + var path = Path.GetFullPath("helllo.txt"); + var contentType = "text/plain; charset=us-ascii; p1=p1-value"; + var expectedMediaType = contentType; + + // Act + var result = new VirtualFileResult(path, contentType); + + // Assert + Assert.Equal(path, result.FileName); + MediaTypeAssert.Equal(expectedMediaType, result.ContentType); + } + + [Theory] + [InlineData(0, 3, "File", 4)] + [InlineData(8, 13, "Result", 6)] + [InlineData(null, 4, "ts¡", 4)] + [InlineData(8, null, "ResultTestFile contents¡", 25)] + public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_WritesRangeRequested( + start, + end, + expectedString, + contentLength, + actionType, + action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest + .WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); + } + + [Theory] + [InlineData("0-5")] + [InlineData("bytes = ")] + [InlineData("bytes = 1-4, 5-11")] + public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest + .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); + } + + [Theory] + [InlineData("bytes = 35-36")] + [InlineData("bytes = -0")] + public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest + .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeRequested_PreconditionFailed() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); + } + + [Fact] + public async Task WriteFileAsync_RangeRequested_NotModified() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest + .ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest + .ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); + } + + [Theory] + [InlineData(0, 3, "File", 4)] + [InlineData(8, 13, "Result", 6)] + [InlineData(null, 3, "ts¡", 3)] + [InlineData(8, null, "ResultTestFile contents¡", 25)] + public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, string expectedString, long contentLength) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + start, + end, + expectedString, + contentLength, + actionType, + action); + } + + [Fact] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_ReturnsFileContentsForRelativePaths(actionType, action); + } + + [Theory] + [InlineData("FilePathResultTestFile.txt")] + [InlineData("TestFiles/FilePathResultTestFile.txt")] + [InlineData("TestFiles/../FilePathResultTestFile.txt")] + [InlineData("TestFiles\\FilePathResultTestFile.txt")] + [InlineData("TestFiles\\..\\FilePathResultTestFile.txt")] + [InlineData(@"\\..//?><|""&@#\c:\..\? /..txt")] + public async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(string path) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest + .ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(path, actionType, action); + } + + [Theory] + [InlineData("~/FilePathResultTestFile.txt")] + [InlineData("~/TestFiles/FilePathResultTestFile.txt")] + [InlineData("~/TestFiles/../FilePathResultTestFile.txt")] + [InlineData("~/TestFiles\\..\\FilePathResultTestFile.txt")] + [InlineData(@"~~~~\\..//?>~<|""&@#\c:\..\? /..txt~~~")] + public async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(string path) + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest + .ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(path, actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_WorksWithNonDiskBasedFiles(actionType, action); + } + + [Fact] + public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile() + { + var actionType = "ActionContext"; + var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile(actionType, action); + } + } +} diff --git a/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs b/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs index 832bcc2acd61..b9bfb75aba2e 100644 --- a/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs @@ -2,59 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Pipelines; -using System.Text; -using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Net.Http.Headers; -using Moq; using Xunit; namespace Microsoft.AspNetCore.Mvc { public class VirtualFileResultTest { - [Fact] - public void Constructor_SetsFileName() - { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - - // Act - var result = new TestVirtualFileResult(path, "text/plain"); - - // Assert - Assert.Equal(path, result.FileName); - } - - [Fact] - public void Constructor_SetsContentTypeAndParameters() - { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var expectedMediaType = contentType; - - // Act - var result = new TestVirtualFileResult(path, contentType); - - // Assert - Assert.Equal(path, result.FileName); - MediaTypeAssert.Equal(expectedMediaType, result.ContentType); - } - [Theory] [InlineData(0, 3, "File", 4)] [InlineData(8, 13, "Result", 6)] @@ -62,181 +17,44 @@ public void Constructor_SetsContentTypeAndParameters() [InlineData(8, null, "ResultTestFile contents¡", 25)] public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - result.EnableRangeProcessing = true; - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var requestHeaders = httpContext.Request.GetTypedHeaders(); - requestHeaders.Range = new RangeHeaderValue(start, end); - requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await result.ExecuteResultAsync(actionContext); - - // Assert - var startResult = start ?? 33 - end; - var endResult = startResult + contentLength - 1; - var httpResponse = actionContext.HttpContext.Response; - var contentRange = new ContentRangeHeaderValue(startResult.Value, endResult.Value, 33); - Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); - Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); - Assert.NotEmpty(httpResponse.Headers.LastModified); - Assert.Equal(contentLength, httpResponse.ContentLength); - Assert.Equal(path, sendFileFeature.Name); - Assert.Equal(startResult, sendFileFeature.Offset); - Assert.Equal((long?)contentLength, sendFileFeature.Length); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_WritesRangeRequested( + start, + end, + expectedString, + contentLength, + actionType, + action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( - string action, - Func function) + [Fact] + public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - result.EnableRangeProcessing = true; - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); - var requestHeaders = httpContext.Request.GetTypedHeaders(); - requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; - requestHeaders.Range = new RangeHeaderValue(0, 3); - requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); - - // Assert - var httpResponse = actionContext.HttpContext.Response; - Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); - var contentRange = new ContentRangeHeaderValue(0, 3, 33); - Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); - Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); - Assert.Equal(4, httpResponse.ContentLength); - Assert.Equal(path, sendFileFeature.Name); - Assert.Equal(0, sendFileFeature.Offset); - Assert.Equal(4, sendFileFeature.Length); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( - string action, - Func function) + [Fact] + public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); - var requestHeaders = httpContext.Request.GetTypedHeaders(); - requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; - requestHeaders.Range = new RangeHeaderValue(0, 3); - requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\"")); - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); - - // Assert - var httpResponse = actionContext.HttpContext.Response; - Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); - Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); - Assert.Equal(path, sendFileFeature.Name); - Assert.Equal(0, sendFileFeature.Offset); - Assert.Null(sendFileFeature.Length); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest + .WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( - string action, - Func function) + [Fact] + public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - result.EnableRangeProcessing = true; - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\""); - var requestHeaders = httpContext.Request.GetTypedHeaders(); - requestHeaders.IfModifiedSince = DateTimeOffset.MinValue; - requestHeaders.Range = new RangeHeaderValue(0, 3); - requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"NotEtag\"")); - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); - - // Assert - var httpResponse = actionContext.HttpContext.Response; - Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); - Assert.Equal(entityTag.ToString(), httpResponse.Headers.ETag); - Assert.Equal(path, sendFileFeature.Name); - Assert.Equal(0, sendFileFeature.Offset); - Assert.Null(sendFileFeature.Length); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); } [Theory] @@ -245,41 +63,11 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( [InlineData("bytes = 1-4, 5-11")] public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - result.EnableRangeProcessing = true; - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var requestHeaders = httpContext.Request.GetTypedHeaders(); - httpContext.Request.Headers.Range = rangeString; - requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await result.ExecuteResultAsync(actionContext); - - // Assert - var httpResponse = actionContext.HttpContext.Response; - Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode); - Assert.Empty(httpResponse.Headers.ContentRange); - Assert.NotEmpty(httpResponse.Headers.LastModified); - Assert.Equal(path, sendFileFeature.Name); - Assert.Equal(0, sendFileFeature.Offset); - Assert.Null(sendFileFeature.Length); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest + .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); } [Theory] @@ -287,192 +75,49 @@ public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string [InlineData("bytes = -0")] public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - result.EnableRangeProcessing = true; - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var httpContext = GetHttpContext(); - httpContext.Response.Body = new MemoryStream(); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var requestHeaders = httpContext.Request.GetTypedHeaders(); - httpContext.Request.Headers.Range = rangeString; - requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); - httpContext.Request.Method = HttpMethods.Get; - httpContext.Response.Body = new MemoryStream(); - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await result.ExecuteResultAsync(actionContext); - - // Assert - var httpResponse = actionContext.HttpContext.Response; - httpResponse.Body.Seek(0, SeekOrigin.Begin); - var streamReader = new StreamReader(httpResponse.Body); - var body = streamReader.ReadToEndAsync().Result; - var contentRange = new ContentRangeHeaderValue(33); - Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); - Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); - Assert.NotEmpty(httpResponse.Headers.LastModified); - Assert.Equal(0, httpResponse.ContentLength); - Assert.Empty(body); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest + .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_RangeRequested_PreconditionFailed( - string action, - Func function) + [Fact] + public async Task WriteFileAsync_RangeRequested_PreconditionFailed() { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - result.EnableRangeProcessing = true; - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var requestHeaders = httpContext.Request.GetTypedHeaders(); - requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue; - httpContext.Request.Headers.Range = "bytes = 0-6"; - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); - - // Assert - var httpResponse = actionContext.HttpContext.Response; - Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode); - Assert.Null(httpResponse.ContentLength); - Assert.Empty(httpResponse.Headers.ContentRange); - Assert.NotEmpty(httpResponse.Headers.LastModified); - Assert.Null(sendFileFeature.Name); // Not called + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task WriteFileAsync_RangeRequested_NotModified( - string action, - Func function) + [Fact] + public async Task WriteFileAsync_RangeRequested_NotModified() { - // Arrange - var path = Path.GetFullPath("helllo.txt"); - var contentType = "text/plain; charset=us-ascii; p1=p1-value"; - var result = new TestVirtualFileResult(path, contentType); - result.EnableRangeProcessing = true; - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var requestHeaders = httpContext.Request.GetTypedHeaders(); - requestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(1); - httpContext.Request.Headers.Range = "bytes = 0-6"; - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); - - // Assert - var httpResponse = actionContext.HttpContext.Response; - Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode); - Assert.Null(httpResponse.ContentLength); - Assert.Empty(httpResponse.Headers.ContentRange); - Assert.NotEmpty(httpResponse.Headers.LastModified); - Assert.False(httpResponse.Headers.ContainsKey(HeaderNames.ContentType)); - Assert.Null(sendFileFeature.Name); // Not called + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent( - string action, - Func function) + [Fact] + public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent() { - // Arrange - var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); - var result = new TestVirtualFileResult(path, "text/plain"); - - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? context : httpContext); - - // Assert - Assert.Equal(path, sendFileFeature.Name); - Assert.Equal(0, sendFileFeature.Offset); - Assert.Null(sendFileFeature.Length); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest + .ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent(actionType, action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( - string action, - Func function) + [Fact] + public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() { - // Arrange - var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); - var result = new TestVirtualFileResult(path, "text/plain") - { - FileProvider = GetFileProvider(path), - }; - - var sendFileMock = new Mock(); - sendFileMock - .Setup(s => s.SendFileAsync(path, 0, null, CancellationToken.None)) - .Returns(Task.FromResult(0)); - - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileMock.Object); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? context : httpContext); - - // Assert - sendFileMock.Verify(); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest + .ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); } [Theory] @@ -482,102 +127,34 @@ public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( [InlineData(8, null, "ResultTestFile contents¡", 25)] public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, string expectedString, long contentLength) { - // Arrange - var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); - var result = new TestVirtualFileResult(path, "text/plain") - { - FileProvider = GetFileProvider(path), - EnableRangeProcessing = true, - }; - - var sendFile = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFile); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - var appEnvironment = new Mock(); - appEnvironment.Setup(app => app.WebRootFileProvider) - .Returns(GetFileProvider(path)); - httpContext.RequestServices = new ServiceCollection() - .AddSingleton(appEnvironment.Object) - .AddTransient, TestVirtualFileResultExecutor>() - .AddTransient() - .BuildServiceProvider(); - - var requestHeaders = httpContext.Request.GetTypedHeaders(); - requestHeaders.Range = new RangeHeaderValue(start, end); - requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue.AddDays(1); - httpContext.Request.Method = HttpMethods.Get; - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await result.ExecuteResultAsync(actionContext); - - // Assert - start = start ?? 33 - end; - end = start + contentLength - 1; - var httpResponse = actionContext.HttpContext.Response; - Assert.Equal(Path.Combine("TestFiles", "FilePathResultTestFile.txt"), sendFile.Name); - Assert.Equal(start, sendFile.Offset); - Assert.Equal(contentLength, sendFile.Length); - Assert.Equal(CancellationToken.None, sendFile.Token); - var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, 33); - Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode); - Assert.Equal("bytes", httpResponse.Headers.AcceptRanges); - Assert.Equal(contentRange.ToString(), httpResponse.Headers.ContentRange); - Assert.NotEmpty(httpResponse.Headers.LastModified); - Assert.Equal(contentLength, httpResponse.ContentLength); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + start, + end, + expectedString, + contentLength, + actionType, + action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( - string action, - Func function) + [Fact] + public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() { - // Arrange - var expectedContentType = "text/foo; charset=us-ascii"; - var result = new TestVirtualFileResult( - "FilePathResultTestFile_ASCII.txt", expectedContentType) - { - FileProvider = GetFileProvider("FilePathResultTestFile_ASCII.txt"), - }; - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? context : httpContext); - - // Assert - Assert.Equal(expectedContentType, httpContext.Response.ContentType); - Assert.Equal("FilePathResultTestFile_ASCII.txt", sendFileFeature.Name); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); } - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths( - string action, - Func function) + [Fact] + public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() { - // Arrange - var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); - var result = new TestVirtualFileResult(path, "text/plain") - { - FileProvider = GetFileProvider(path), - }; - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await function(result, action == "ActionContext" ? context : httpContext); - - // Assert - Assert.Equal(path, sendFileFeature.Name); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + + await BaseVirtualFileResultTest.ExecuteResultAsync_ReturnsFileContentsForRelativePaths(actionType, action); } [Theory] @@ -589,24 +166,11 @@ public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths( [InlineData(@"\\..//?><|""&@#\c:\..\? /..txt")] public async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(string path) { - // Arrange - var result = new TestVirtualFileResult(path, "text/plain") - { - FileProvider = GetFileProvider(path), - }; - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await result.ExecuteResultAsync(context); - - // Assert - Mock.Get(result.FileProvider).Verify(); - Assert.Equal(path, sendFileFeature.Name); + await BaseVirtualFileResultTest + .ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(path, actionType, action); } [Theory] @@ -617,200 +181,29 @@ public async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(string path) [InlineData(@"~~~~\\..//?>~<|""&@#\c:\..\? /..txt~~~")] public async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(string path) { - // Arrange - var expectedPath = path.Substring(1); - var result = new TestVirtualFileResult(path, "text/plain") - { - FileProvider = GetFileProvider(expectedPath), - }; - - var sendFileFeature = new TestSendFileFeature(); - var httpContext = GetHttpContext(); - httpContext.Features.Set(sendFileFeature); - - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - - // Act - await result.ExecuteResultAsync(context); - - // Assert - Mock.Get(result.FileProvider).Verify(); - Assert.Equal(expectedPath, sendFileFeature.Name); - } - - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles( - string action, - Func function) - { - // Arrange - var httpContext = GetHttpContext(typeof(VirtualFileResultExecutor)); - httpContext.Response.Body = new MemoryStream(); - var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); - var expectedData = "This is an embedded resource"; - var sourceStream = new MemoryStream(Encoding.UTF8.GetBytes(expectedData)); - - var nonDiskFileInfo = new Mock(); - nonDiskFileInfo.SetupGet(fi => fi.Exists).Returns(true); - nonDiskFileInfo.SetupGet(fi => fi.PhysicalPath).Returns(() => null); // set null to indicate non-disk file - nonDiskFileInfo.Setup(fi => fi.CreateReadStream()).Returns(sourceStream); - var nonDiskFileProvider = new Mock(); - nonDiskFileProvider.Setup(fp => fp.GetFileInfo(It.IsAny())).Returns(nonDiskFileInfo.Object); - - var filePathResult = new VirtualFileResult("/SampleEmbeddedFile.txt", "text/plain") - { - FileProvider = nonDiskFileProvider.Object - }; - - // Act - await function(filePathResult, action == "ActionContext" ? actionContext : httpContext); - - // Assert - httpContext.Response.Body.Position = 0; - var contents = await new StreamReader(httpContext.Response.Body).ReadToEndAsync(); - Assert.Equal(expectedData, contents); - } + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - [Theory] - [MemberData(nameof(GetActions))] - public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile( - string action, - Func function) - { - // Arrange - var path = "TestPath.txt"; - var fileInfo = new Mock(); - fileInfo.SetupGet(f => f.Exists).Returns(false); - var fileProvider = new Mock(); - fileProvider.Setup(f => f.GetFileInfo(path)).Returns(fileInfo.Object); - var filePathResult = new TestVirtualFileResult(path, "text/plain") - { - FileProvider = fileProvider.Object, - }; - - var expectedMessage = "Could not find file: " + path; - var context = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); - - // Act - var ex = await Assert.ThrowsAsync(() => function(filePathResult, action == "ActionContext" ? context : context.HttpContext)); - - // Assert - Assert.Equal(expectedMessage, ex.Message); - Assert.Equal(path, ex.FileName); + await BaseVirtualFileResultTest + .ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(path, actionType, action); } - public static IEnumerable GetActions() - { - return new List - { - new object[] { "ActionContext", new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)) }, - new object[] { "HttpContext", new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)) }, - }; - } - - private static IServiceCollection CreateServices(Type executorType) - { - var services = new ServiceCollection(); - - var hostingEnvironment = new Mock(); - - services.AddSingleton, TestVirtualFileResultExecutor>(); - if (executorType != null) - { - services.AddSingleton(typeof(IActionResultExecutor), executorType); - } - - services.AddSingleton(hostingEnvironment.Object); - services.AddSingleton(NullLoggerFactory.Instance); - - return services; - } - - private static HttpContext GetHttpContext(Type executorType = null) - { - var services = CreateServices(executorType); - - var httpContext = new DefaultHttpContext(); - httpContext.RequestServices = services.BuildServiceProvider(); - - return httpContext; - } - - private static IFileProvider GetFileProvider(string path) + [Fact] + public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles() { - var fileInfo = new Mock(); - fileInfo.SetupGet(fi => fi.Length).Returns(33); - fileInfo.SetupGet(fi => fi.Exists).Returns(true); - var lastModified = DateTimeOffset.MinValue.AddDays(1); - lastModified = new DateTimeOffset(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, TimeSpan.FromSeconds(0)); - fileInfo.SetupGet(fi => fi.LastModified).Returns(lastModified); - fileInfo.SetupGet(fi => fi.PhysicalPath).Returns(path); - var fileProvider = new Mock(); - fileProvider.Setup(fp => fp.GetFileInfo(path)) - .Returns(fileInfo.Object) - .Verifiable(); - - return fileProvider.Object; - } + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - private class TestVirtualFileResult : VirtualFileResult - { - public TestVirtualFileResult(string filePath, string contentType) - : base(filePath, contentType) - { - } - - public override Task ExecuteResultAsync(ActionContext context) - { - var executor = (TestVirtualFileResultExecutor)context.HttpContext.RequestServices.GetRequiredService>(); - return executor.ExecuteAsync(context, this); - } + await BaseVirtualFileResultTest.ExecuteResultAsync_WorksWithNonDiskBasedFiles(actionType, action); } - private class TestVirtualFileResultExecutor : VirtualFileResultExecutor + [Fact] + public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile() { - public TestVirtualFileResultExecutor(ILoggerFactory loggerFactory, IWebHostEnvironment hostingEnvironment) - : base(loggerFactory, hostingEnvironment) - { - } - } + var actionType = "HttpContext"; + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - private class TestSendFileFeature : IHttpResponseBodyFeature - { - public string Name { get; set; } - public long Offset { get; set; } - public long? Length { get; set; } - public CancellationToken Token { get; set; } - - public Stream Stream => throw new NotImplementedException(); - - public PipeWriter Writer => throw new NotImplementedException(); - - public Task CompleteAsync() - { - throw new NotImplementedException(); - } - - public void DisableBuffering() - { - throw new NotImplementedException(); - } - - public Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) - { - Name = path; - Offset = offset; - Length = length; - Token = cancellation; - - return Task.FromResult(0); - } - - public Task StartAsync(CancellationToken cancellation = default) - { - throw new NotImplementedException(); - } + await BaseVirtualFileResultTest.ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile(actionType, action); } } } From 0418d286ca2b136748b98a4660c4c2de67ca6cb7 Mon Sep 17 00:00:00 2001 From: Juan Barahona Date: Fri, 21 May 2021 01:33:11 -0400 Subject: [PATCH 5/5] Applying observations for generics and identations --- .../test/BaseFileContentResultTest.cs | 84 +++++----- .../test/BasePhysicalFileResultTest.cs | 132 +++++++-------- .../Mvc.Core/test/BaseRedirectResultTest.cs | 25 +-- .../test/BaseVirtualFileResultTest.cs | 150 +++++++++--------- .../test/FileContentActionResultTest.cs | 52 +++--- src/Mvc/Mvc.Core/test/FileContentResult.cs | 54 +++---- .../test/PhysicalFileActionResultTest.cs | 82 ++++------ src/Mvc/Mvc.Core/test/PhysicalFileResult.cs | 84 ++++------ .../Mvc.Core/test/RedirectActionResultTest.cs | 10 +- src/Mvc/Mvc.Core/test/RedirectResultTest.cs | 10 +- .../test/VirtualFileActionResultTest .cs | 89 ++++------- .../Mvc.Core/test/VirtualFileResultTest.cs | 86 ++++------ 12 files changed, 366 insertions(+), 492 deletions(-) diff --git a/src/Mvc/Mvc.Core/test/BaseFileContentResultTest.cs b/src/Mvc/Mvc.Core/test/BaseFileContentResultTest.cs index 1ce224f8246a..cb397e816a81 100644 --- a/src/Mvc/Mvc.Core/test/BaseFileContentResultTest.cs +++ b/src/Mvc/Mvc.Core/test/BaseFileContentResultTest.cs @@ -19,9 +19,8 @@ namespace Microsoft.AspNetCore.Mvc { public class BaseFileContentResultTest { - public static async Task WriteFileAsync_CopiesBuffer_ToOutputStream( - string action, - Func function) + public static async Task WriteFileAsync_CopiesBuffer_ToOutputStream( + Func function) { // Arrange var buffer = new byte[] { 1, 2, 3, 4, 5 }; @@ -31,24 +30,24 @@ public static async Task WriteFileAsync_CopiesBuffer_ToOutputStream( var outStream = new MemoryStream(); httpContext.Response.Body = outStream; - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileContentResult(buffer, "text/plain"); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Assert.Equal(buffer, outStream.ToArray()); } - public static async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested( + public static async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested( long? start, long? end, string expectedString, long contentLength, - string action, - Func function) + Func function) { // Arrange var contentType = "text/plain"; @@ -75,7 +74,8 @@ public static async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRan var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert start = start ?? 11 - end; @@ -94,9 +94,8 @@ public static async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRan Assert.Equal(expectedString, body); } - public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( - string action, - Func function) + public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( + Func function) { // Arrange var contentType = "text/plain"; @@ -124,7 +123,8 @@ public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -151,9 +151,8 @@ public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest( } } - public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored( - string action, - Func function) + public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored( + Func function) { // Arrange var contentType = "text/plain"; @@ -180,7 +179,8 @@ public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIg var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -193,9 +193,8 @@ public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIg Assert.Equal("Hello World", body); } - public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored( - string action, - Func function) + public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored( + Func function) { // Arrange var contentType = "text/plain"; @@ -223,7 +222,8 @@ public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -236,10 +236,9 @@ public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored Assert.Equal("Hello World", body); } - public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored( + public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored( string rangeString, - string action, - Func function) + Func function) { // Arrange var contentType = "text/plain"; @@ -261,7 +260,8 @@ public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeReques var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -275,10 +275,9 @@ public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeReques Assert.Equal("Hello World", body); } - public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable( + public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable( string rangeString, - string action, - Func function) + Func function) { // Arrange var contentType = "text/plain"; @@ -300,7 +299,8 @@ public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeReques var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -317,9 +317,8 @@ public static async Task WriteFileAsync_PreconditionStateUnspecified_RangeReques Assert.Empty(body); } - public static async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored( - string action, - Func function) + public static async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored( + Func function) { // Arrange var contentType = "text/plain"; @@ -346,7 +345,8 @@ public static async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -360,9 +360,8 @@ public static async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored Assert.Empty(body); } - public static async Task WriteFileAsync_NotModified_RangeRequestedIgnored( - string action, - Func function) + public static async Task WriteFileAsync_NotModified_RangeRequestedIgnored( + Func function) { // Arrange var contentType = "text/plain"; @@ -389,7 +388,8 @@ public static async Task WriteFileAsync_NotModified_RangeRequestedIgnored( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -404,9 +404,8 @@ public static async Task WriteFileAsync_NotModified_RangeRequestedIgnored( Assert.Empty(body); } - public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( - string action, - Func function) + public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + Func function) { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; @@ -417,12 +416,13 @@ public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( var outStream = new MemoryStream(); httpContext.Response.Body = outStream; - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var result = new FileContentResult(buffer, expectedContentType); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Assert.Equal(buffer, outStream.ToArray()); diff --git a/src/Mvc/Mvc.Core/test/BasePhysicalFileResultTest.cs b/src/Mvc/Mvc.Core/test/BasePhysicalFileResultTest.cs index 331fac3d0c4c..c4d8960e879e 100644 --- a/src/Mvc/Mvc.Core/test/BasePhysicalFileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/BasePhysicalFileResultTest.cs @@ -23,13 +23,12 @@ namespace Microsoft.AspNetCore.Mvc { public class BasePhysicalFileResultTest { - public static async Task WriteFileAsync_WritesRangeRequested( + public static async Task WriteFileAsync_WritesRangeRequested( long? start, long? end, string expectedString, long contentLength, - string action, - Func function) + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -45,7 +44,8 @@ public static async Task WriteFileAsync_WritesRangeRequested( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var startResult = start ?? 34 - end; @@ -62,9 +62,8 @@ public static async Task WriteFileAsync_WritesRangeRequested( Assert.Equal((long?)contentLength, sendFile.Length); } - public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( - string action, - Func function) + public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -82,7 +81,8 @@ public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -98,9 +98,8 @@ public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( Assert.Equal(4, sendFile.Length); } - public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( - string action, - Func function) + public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -117,7 +116,8 @@ public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequested var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -128,9 +128,8 @@ public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequested Assert.Null(sendFile.Length); } - public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( - string action, - Func function) + public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -148,7 +147,8 @@ public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnor var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -159,10 +159,9 @@ public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnor Assert.Null(sendFile.Length); } - public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored( + public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored( string rangeString, - string action, - Func function) + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -177,7 +176,8 @@ public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -189,10 +189,9 @@ public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored Assert.Null(sendFile.Length); } - public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( + public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( string rangeString, - string action, - Func function) + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -207,7 +206,8 @@ public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -223,9 +223,8 @@ public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( Assert.Empty(body); } - public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( - string action, - Func function) + public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -240,7 +239,8 @@ public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -254,9 +254,8 @@ public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( Assert.Empty(body); } - public static async Task WriteFileAsync_RangeRequested_NotModified( - string action, - Func function) + public static async Task WriteFileAsync_RangeRequested_NotModified( + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -271,7 +270,8 @@ public static async Task WriteFileAsync_RangeRequested_NotModified( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -286,9 +286,8 @@ public static async Task WriteFileAsync_RangeRequested_NotModified( Assert.Empty(body); } - public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( - string action, - Func function) + public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -300,21 +299,21 @@ public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePr var httpContext = GetHttpContext(); httpContext.Features.Set(sendFileMock.Object); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert sendFileMock.Verify(); } - public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( long? start, long? end, long contentLength, - string action, - Func function) + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")); @@ -331,7 +330,8 @@ public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object functionContext = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)functionContext); // Assert start = start ?? 34 - end; @@ -349,9 +349,8 @@ public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange Assert.Equal(contentLength, httpResponse.ContentLength); } - public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( - string action, - Func function) + public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + Func function) { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; @@ -360,10 +359,11 @@ public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( var sendFile = new TestSendFileFeature(); var httpContext = GetHttpContext(); httpContext.Features.Set(sendFile); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Assert.Equal(expectedContentType, httpContext.Response.ContentType); @@ -373,9 +373,8 @@ public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( Assert.Equal(CancellationToken.None, sendFile.Token); } - public static async Task ExecuteResultAsync_WorksWithAbsolutePaths( - string action, - Func function) + public static async Task ExecuteResultAsync_WorksWithAbsolutePaths( + Func function) { // Arrange var path = Path.GetFullPath(Path.Combine(".", "TestFiles", "FilePathResultTestFile.txt")); @@ -385,10 +384,11 @@ public static async Task ExecuteResultAsync_WorksWithAbsolutePaths( var httpContext = GetHttpContext(); httpContext.Features.Set(sendFile); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Assert.Equal(Path.GetFullPath(Path.Combine(".", "TestFiles", "FilePathResultTestFile.txt")), sendFile.Name); @@ -397,50 +397,50 @@ public static async Task ExecuteResultAsync_WorksWithAbsolutePaths( Assert.Equal(CancellationToken.None, sendFile.Token); } - public static async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths( + public static async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths( string path, - string action, - Func function) + Func function) { // Arrange var result = new TestPhysicalFileResult(path, "text/plain"); - var context = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); var expectedMessage = $"Path '{path}' was not rooted."; // Act + object context = typeof(TContext) == typeof(HttpContext) ? actionContext.HttpContext : actionContext; var ex = await Assert.ThrowsAsync( - () => function(result, action == "ActionContext" ? context : context.HttpContext)); + () => function(result, (TContext)context)); // Assert Assert.Equal(expectedMessage, ex.Message); } - public static void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths( + public static void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths( string path, - string action, - Func function) + Func function) { // Arrange var result = new TestPhysicalFileResult(path, "text/plain"); - var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); // Act & Assert + object context = typeof(TContext) == typeof(HttpContext) ? actionContext.HttpContext : actionContext; Assert.ThrowsAsync( - () => function(result, action == "ActionContext" ? context : context.HttpContext)); + () => function(result, (TContext)context)); } - public static void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths( + public static void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths( string path, - string action, - Func function) + Func function) { // Arrange var result = new TestPhysicalFileResult(path, "text/plain"); - var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); // Act & Assert + object context = typeof(TContext) == typeof(HttpContext) ? actionContext.HttpContext : actionContext; Assert.ThrowsAsync( - () => function(result, action == "ActionContext" ? context : context.HttpContext)); + () => function(result, (TContext)context)); } private class TestPhysicalFileResult : PhysicalFileResult, IResult diff --git a/src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs b/src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs index 733b93715e0a..6097a09263ec 100644 --- a/src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs +++ b/src/Mvc/Mvc.Core/test/BaseRedirectResultTest.cs @@ -17,12 +17,11 @@ namespace Microsoft.AspNetCore.Mvc { public class BaseRedirectResultTest { - public static async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( + public static async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( string appRoot, string contentPath, string expectedPath, - string action, - Func function) + Func function) { // Arrange var httpContext = GetHttpContext(appRoot); @@ -30,7 +29,8 @@ public static async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( var result = new RedirectResult(contentPath); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext) context); // Assert // Verifying if Redirect was called with the specific Url and parameter flag. @@ -38,12 +38,11 @@ public static async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode); } - public static async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( + public static async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( string appRoot, string contentPath, string expectedPath, - string action, - Func function) + Func function) { // Arrange var httpContext = GetHttpContext(appRoot); @@ -51,7 +50,8 @@ public static async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( var result = new RedirectResult(contentPath); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert // Verifying if Redirect was called with the specific Url and parameter flag. @@ -62,11 +62,12 @@ public static async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( private static ActionContext GetActionContext(HttpContext httpContext) { var routeData = new RouteData(); - routeData.Routers.Add(new Mock().Object); + routeData.Routers.Add(Mock.Of()); - return new ActionContext(httpContext, - routeData, - new ActionDescriptor()); + return new ActionContext( + httpContext, + routeData, + new ActionDescriptor()); } private static IServiceProvider GetServiceProvider() diff --git a/src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs b/src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs index ae9e4d37f370..727d18eadb8f 100644 --- a/src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/BaseVirtualFileResultTest.cs @@ -25,13 +25,12 @@ namespace Microsoft.AspNetCore.Mvc { public class BaseVirtualFileResultTest { - public static async Task WriteFileAsync_WritesRangeRequested( + public static async Task WriteFileAsync_WritesRangeRequested( long? start, long? end, string expectedString, long contentLength, - string action, - Func function) + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -58,7 +57,8 @@ public static async Task WriteFileAsync_WritesRangeRequested( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var startResult = start ?? 33 - end; @@ -75,9 +75,8 @@ public static async Task WriteFileAsync_WritesRangeRequested( Assert.Equal((long?)contentLength, sendFileFeature.Length); } - public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( - string action, - Func function) + public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -106,7 +105,8 @@ public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -121,9 +121,8 @@ public static async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange( Assert.Equal(4, sendFileFeature.Length); } - public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( - string action, - Func function) + public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored( + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -151,7 +150,8 @@ public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequested var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -162,9 +162,8 @@ public static async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequested Assert.Null(sendFileFeature.Length); } - public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( - string action, - Func function) + public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored( + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -193,7 +192,8 @@ public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnor var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -204,10 +204,9 @@ public static async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnor Assert.Null(sendFileFeature.Length); } - public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored( + public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored( string rangeString, - string action, - Func function) + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -234,7 +233,8 @@ public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -246,10 +246,9 @@ public static async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored Assert.Null(sendFileFeature.Length); } - public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( + public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( string rangeString, - string action, - Func function) + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -276,7 +275,8 @@ public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -292,9 +292,8 @@ public static async Task WriteFileAsync_RangeRequestedNotSatisfiable( Assert.Empty(body); } - public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( - string action, - Func function) + public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -321,7 +320,8 @@ public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -332,9 +332,8 @@ public static async Task WriteFileAsync_RangeRequested_PreconditionFailed( Assert.Null(sendFileFeature.Name); // Not called } - public static async Task WriteFileAsync_RangeRequested_NotModified( - string action, - Func function) + public static async Task WriteFileAsync_RangeRequested_NotModified( + Func function) { // Arrange var path = Path.GetFullPath("helllo.txt"); @@ -361,7 +360,8 @@ public static async Task WriteFileAsync_RangeRequested_NotModified( var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert var httpResponse = actionContext.HttpContext.Response; @@ -373,9 +373,8 @@ public static async Task WriteFileAsync_RangeRequested_NotModified( Assert.Null(sendFileFeature.Name); // Not called } - public static async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent( - string action, - Func function) + public static async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent( + Func function) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); @@ -393,10 +392,11 @@ public static async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoF .AddTransient, TestVirtualFileResultExecutor>() .AddTransient() .BuildServiceProvider(); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Assert.Equal(path, sendFileFeature.Name); @@ -404,9 +404,8 @@ public static async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoF Assert.Null(sendFileFeature.Length); } - public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( - string action, - Func function) + public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent( + Func function) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); @@ -422,21 +421,21 @@ public static async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePr var httpContext = GetHttpContext(); httpContext.Features.Set(sendFileMock.Object); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert sendFileMock.Verify(); } - public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( + public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( long? start, long? end, string expectedString, long contentLength, - string action, - Func function) + Func function) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); @@ -466,7 +465,8 @@ public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? actionContext : httpContext); + object functionContext = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext) functionContext); // Assert start = start ?? 33 - end; @@ -484,9 +484,8 @@ public static async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange Assert.Equal(contentLength, httpResponse.ContentLength); } - public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( - string action, - Func function) + public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( + Func function) { // Arrange var expectedContentType = "text/foo; charset=us-ascii"; @@ -499,19 +498,19 @@ public static async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding( var sendFileFeature = new TestSendFileFeature(); var httpContext = GetHttpContext(); httpContext.Features.Set(sendFileFeature); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Assert.Equal(expectedContentType, httpContext.Response.ContentType); Assert.Equal("FilePathResultTestFile_ASCII.txt", sendFileFeature.Name); } - public static async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths( - string action, - Func function) + public static async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths( + Func function) { // Arrange var path = Path.Combine("TestFiles", "FilePathResultTestFile.txt"); @@ -523,19 +522,19 @@ public static async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths( var sendFileFeature = new TestSendFileFeature(); var httpContext = GetHttpContext(); httpContext.Features.Set(sendFileFeature); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Assert.Equal(path, sendFileFeature.Name); } - public static async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths( + public static async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths( string path, - string action, - Func function) + Func function) { // Arrange var result = new TestVirtualFileResult(path, "text/plain") @@ -547,20 +546,20 @@ public static async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths( var httpContext = GetHttpContext(); httpContext.Features.Set(sendFileFeature); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Mock.Get(result.FileProvider).Verify(); Assert.Equal(path, sendFileFeature.Name); } - public static async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider( + public static async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider( string path, - string action, - Func function) + Func function) { // Arrange var expectedPath = path.Substring(1); @@ -573,19 +572,19 @@ public static async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvide var httpContext = GetHttpContext(); httpContext.Features.Set(sendFileFeature); - var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // Act - await function(result, action == "ActionContext" ? context : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(result, (TContext)context); // Assert Mock.Get(result.FileProvider).Verify(); Assert.Equal(expectedPath, sendFileFeature.Name); } - public static async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles( - string action, - Func function) + public static async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles( + Func function) { // Arrange var httpContext = GetHttpContext(typeof(VirtualFileResultExecutor)); @@ -607,7 +606,8 @@ public static async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles( }; // Act - await function(filePathResult, action == "ActionContext" ? actionContext : httpContext); + object context = typeof(TContext) == typeof(HttpContext) ? httpContext : actionContext; + await function(filePathResult, (TContext)context); // Assert httpContext.Response.Body.Position = 0; @@ -615,9 +615,8 @@ public static async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles( Assert.Equal(expectedData, contents); } - public static async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile( - string action, - Func function) + public static async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile( + Func function) { // Arrange var path = "TestPath.txt"; @@ -631,10 +630,11 @@ public static async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCan }; var expectedMessage = "Could not find file: " + path; - var context = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); + var actionContext = new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor()); // Act - var ex = await Assert.ThrowsAsync(() => function(filePathResult, action == "ActionContext" ? context : context.HttpContext)); + object context = typeof(TContext) == typeof(HttpContext) ? actionContext.HttpContext : actionContext; + var ex = await Assert.ThrowsAsync(() => function(filePathResult, (TContext)context)); // Assert Assert.Equal(expectedMessage, ex.Message); diff --git a/src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs b/src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs index 958a665b3908..a8e91fddd761 100644 --- a/src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs +++ b/src/Mvc/Mvc.Core/test/FileContentActionResultTest.cs @@ -65,10 +65,9 @@ public void Constructor_SetsLastModifiedAndEtag() [Fact] public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_CopiesBuffer_ToOutputStream(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_CopiesBuffer_ToOutputStream(action); } [Theory] @@ -78,38 +77,34 @@ public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() [InlineData(6, null, "World", 5)] public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseFileContentResultTest - .WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(start, end, expectedString, contentLength, actionType, action); + .WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(start, end, expectedString, contentLength, action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest(action); } [Fact] public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored(action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored(action); } [Theory] @@ -118,11 +113,9 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() [InlineData("bytes = 1-4, 5-11")] public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(string rangeString) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest - .WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(rangeString, actionType, action); + await BaseFileContentResultTest.WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(rangeString, action); } [Theory] @@ -130,38 +123,33 @@ await BaseFileContentResultTest [InlineData("bytes = -0")] public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest - .WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(rangeString, actionType, action); + await BaseFileContentResultTest.WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(rangeString, action); } [Fact] public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_PreconditionFailed_RangeRequestedIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_PreconditionFailed_RangeRequestedIgnored(action); } [Fact] public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_NotModified_RangeRequestedIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_NotModified_RangeRequestedIgnored(action); } [Fact] public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseFileContentResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + await BaseFileContentResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(action); } } } diff --git a/src/Mvc/Mvc.Core/test/FileContentResult.cs b/src/Mvc/Mvc.Core/test/FileContentResult.cs index 32f5e2ea2e2b..7be596c7ee6a 100644 --- a/src/Mvc/Mvc.Core/test/FileContentResult.cs +++ b/src/Mvc/Mvc.Core/test/FileContentResult.cs @@ -12,11 +12,8 @@ public class FileContentResultTest { [Fact] public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() - { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - - await BaseFileContentResultTest.WriteFileAsync_CopiesBuffer_ToOutputStream(actionType, action); + {var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); + await BaseFileContentResultTest.WriteFileAsync_CopiesBuffer_ToOutputStream(action); } [Theory] @@ -26,38 +23,34 @@ public async Task WriteFileAsync_CopiesBuffer_ToOutputStream() [InlineData(6, null, "World", 5)] public async Task WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseFileContentResultTest - .WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(start, end, expectedString, contentLength, actionType, action); + .WriteFileAsync_PreconditionStateShouldProcess_WritesRangeRequested(start, end, expectedString, contentLength, action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest(action); } [Fact] public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored(action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored(action); } [Theory] @@ -66,11 +59,9 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored() [InlineData("bytes = 1-4, 5-11")] public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(string rangeString) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest - .WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(rangeString, actionType, action); + await BaseFileContentResultTest.WriteFileAsync_PreconditionStateUnspecified_RangeRequestIgnored(rangeString, action); } [Theory] @@ -78,38 +69,33 @@ await BaseFileContentResultTest [InlineData("bytes = -0")] public async Task WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(string rangeString) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest - .WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(rangeString, actionType, action); + await BaseFileContentResultTest.WriteFileAsync_PreconditionStateUnspecified_RangeRequestedNotSatisfiable(rangeString, action); } [Fact] public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_PreconditionFailed_RangeRequestedIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_PreconditionFailed_RangeRequestedIgnored(action); } [Fact] public async Task WriteFileAsync_NotModified_RangeRequestedIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest.WriteFileAsync_NotModified_RangeRequestedIgnored(actionType, action); + await BaseFileContentResultTest.WriteFileAsync_NotModified_RangeRequestedIgnored(action); } [Fact] public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseFileContentResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + await BaseFileContentResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(action); } } } diff --git a/src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs b/src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs index 654c656ec9a3..7677af32f434 100644 --- a/src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs +++ b/src/Mvc/Mvc.Core/test/PhysicalFileActionResultTest.cs @@ -46,43 +46,38 @@ public void Constructor_SetsContentTypeAndParameters() [InlineData(8, null, "ResultTestFile contents�", 26)] public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BasePhysicalFileResultTest.WriteFileAsync_WritesRangeRequested( start, end, expectedString, contentLength, - actionType, action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(action); } [Fact] public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(action); } [Theory] @@ -91,11 +86,9 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() [InlineData("bytes = 1-4, 5-11")] public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest - .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, action); } [Theory] @@ -103,38 +96,33 @@ await BasePhysicalFileResultTest [InlineData("bytes = -0")] public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest - .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, action); } [Fact] public async Task WriteFileAsync_RangeRequested_PreconditionFailed() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(action); } [Fact] public async Task WriteFileAsync_RangeRequested_NotModified() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_NotModified(action); } [Fact] public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(action); } [Theory] @@ -144,33 +132,25 @@ public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() [InlineData(8, null, 26)] public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, long contentLength) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( - start, - end, - contentLength, - actionType, - action); + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(start, end, contentLength, action); } [Fact] public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + await BasePhysicalFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(action); } [Fact] public async Task ExecuteResultAsync_WorksWithAbsolutePaths() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_WorksWithAbsolutePaths(actionType, action); + await BasePhysicalFileResultTest.ExecuteResultAsync_WorksWithAbsolutePaths(action); } [Theory] @@ -188,11 +168,9 @@ public async Task ExecuteResultAsync_WorksWithAbsolutePaths() [InlineData("~/SubFolder\\SubFolderTestFile.txt")] public async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(string path) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BasePhysicalFileResultTest - .ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(path, actionType, action); + await BasePhysicalFileResultTest.ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(path, action); } [Theory] @@ -206,11 +184,10 @@ await BasePhysicalFileResultTest [InlineData(".\\SubFolder/SubFolderTestFile.txt")] public void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(string path) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); BasePhysicalFileResultTest - .ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(path, actionType, action); + .ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(path, action); } [Theory] @@ -218,11 +195,10 @@ public void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForR [InlineData("\\FilePathResultTestFile.txt")] public void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(string path) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); BasePhysicalFileResultTest - .ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(path, actionType, action); + .ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(path, action); } } } diff --git a/src/Mvc/Mvc.Core/test/PhysicalFileResult.cs b/src/Mvc/Mvc.Core/test/PhysicalFileResult.cs index ddc67627bae6..5cadbb3db739 100644 --- a/src/Mvc/Mvc.Core/test/PhysicalFileResult.cs +++ b/src/Mvc/Mvc.Core/test/PhysicalFileResult.cs @@ -17,43 +17,38 @@ public class PhysicalFileResultTest [InlineData(8, null, "ResultTestFile contents�", 26)] public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BasePhysicalFileResultTest.WriteFileAsync_WritesRangeRequested( start, end, expectedString, contentLength, - actionType, action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(action); } [Fact] public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(action); } [Theory] @@ -62,11 +57,9 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() [InlineData("bytes = 1-4, 5-11")] public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest - .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, action); } [Theory] @@ -74,38 +67,31 @@ await BasePhysicalFileResultTest [InlineData("bytes = -0")] public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest - .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, action); } [Fact] public async Task WriteFileAsync_RangeRequested_PreconditionFailed() - { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); - - await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); + {var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(action); } [Fact] public async Task WriteFileAsync_RangeRequested_NotModified() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); + await BasePhysicalFileResultTest.WriteFileAsync_RangeRequested_NotModified(action); } [Fact] public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(action); } [Theory] @@ -115,33 +101,25 @@ public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() [InlineData(8, null, 26)] public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, long contentLength) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( - start, - end, - contentLength, - actionType, - action); + await BasePhysicalFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(start, end, contentLength, action); } [Fact] public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + await BasePhysicalFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(action); } [Fact] public async Task ExecuteResultAsync_WorksWithAbsolutePaths() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest.ExecuteResultAsync_WorksWithAbsolutePaths(actionType, action); + await BasePhysicalFileResultTest.ExecuteResultAsync_WorksWithAbsolutePaths(action); } [Theory] @@ -159,11 +137,9 @@ public async Task ExecuteResultAsync_WorksWithAbsolutePaths() [InlineData("~/SubFolder\\SubFolderTestFile.txt")] public async Task ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(string path) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BasePhysicalFileResultTest - .ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(path, actionType, action); + await BasePhysicalFileResultTest.ExecuteAsync_ThrowsNotSupported_ForNonRootedPaths(path, action); } [Theory] @@ -177,11 +153,10 @@ await BasePhysicalFileResultTest [InlineData(".\\SubFolder/SubFolderTestFile.txt")] public void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(string path) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); BasePhysicalFileResultTest - .ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(path, actionType, action); + .ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForRootPaths(path, action); } [Theory] @@ -189,11 +164,10 @@ public void ExecuteAsync_ThrowsDirectoryNotFound_IfItCanNotFindTheDirectory_ForR [InlineData("\\FilePathResultTestFile.txt")] public void ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(string path) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); BasePhysicalFileResultTest - .ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(path, actionType, action); + .ExecuteAsync_ThrowsFileNotFound_WhenFileDoesNotExist_ForRootPaths(path, action); } } } diff --git a/src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs b/src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs index fbaa5642626b..9b139431fd88 100644 --- a/src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs +++ b/src/Mvc/Mvc.Core/test/RedirectActionResultTest.cs @@ -62,14 +62,13 @@ public async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( string contentPath, string expectedPath) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action + = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseRedirectResultTest.Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( appRoot, contentPath, expectedPath, - actionType, action); } @@ -84,14 +83,13 @@ public async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( string contentPath, string expectedPath) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = + new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseRedirectResultTest.Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( appRoot, contentPath, expectedPath, - actionType, action); } } diff --git a/src/Mvc/Mvc.Core/test/RedirectResultTest.cs b/src/Mvc/Mvc.Core/test/RedirectResultTest.cs index c32c51cf6780..68e310a82aac 100644 --- a/src/Mvc/Mvc.Core/test/RedirectResultTest.cs +++ b/src/Mvc/Mvc.Core/test/RedirectResultTest.cs @@ -18,14 +18,13 @@ public async Task Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( string contentPath, string expectedPath) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action + = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseRedirectResultTest.Execute_ReturnsContentPath_WhenItDoesNotStartWithTilde( appRoot, contentPath, expectedPath, - actionType, action); } @@ -40,14 +39,13 @@ public async Task Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( string contentPath, string expectedPath) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action + = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseRedirectResultTest.Execute_ReturnsAppRelativePath_WhenItStartsWithTilde( appRoot, contentPath, expectedPath, - actionType, action); } } diff --git a/src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs b/src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs index 5a6afc6c7656..ebc4f89f903e 100644 --- a/src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs +++ b/src/Mvc/Mvc.Core/test/VirtualFileActionResultTest .cs @@ -46,44 +46,38 @@ public void Constructor_SetsContentTypeAndParameters() [InlineData(8, null, "ResultTestFile contents¡", 25)] public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseVirtualFileResultTest.WriteFileAsync_WritesRangeRequested( start, end, expectedString, contentLength, - actionType, action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(action); } [Fact] public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseVirtualFileResultTest - .WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); + .WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); - - await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(action); } [Theory] @@ -92,11 +86,8 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() [InlineData("bytes = 1-4, 5-11")] public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); - - await BaseVirtualFileResultTest - .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); + await BaseVirtualFileResultTest.WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, action); } [Theory] @@ -104,49 +95,41 @@ await BaseVirtualFileResultTest [InlineData("bytes = -0")] public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); - - await BaseVirtualFileResultTest - .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, action); } [Fact] public async Task WriteFileAsync_RangeRequested_PreconditionFailed() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); - - await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(action); } [Fact] public async Task WriteFileAsync_RangeRequested_NotModified() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_NotModified(action); } [Fact] public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent(actionType, action); + .ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent(action); } [Fact] public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); + .ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(action); } [Theory] @@ -156,34 +139,30 @@ await BaseVirtualFileResultTest [InlineData(8, null, "ResultTestFile contents¡", 25)] public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, string expectedString, long contentLength) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseVirtualFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( start, end, expectedString, contentLength, - actionType, action); } [Fact] public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(action); } [Fact] public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_ReturnsFileContentsForRelativePaths(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_ReturnsFileContentsForRelativePaths(action); } [Theory] @@ -195,11 +174,10 @@ public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() [InlineData(@"\\..//?><|""&@#\c:\..\? /..txt")] public async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(string path) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(path, actionType, action); + .ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(path, action); } [Theory] @@ -210,29 +188,26 @@ await BaseVirtualFileResultTest [InlineData(@"~~~~\\..//?>~<|""&@#\c:\..\? /..txt~~~")] public async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(string path) { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(path, actionType, action); + .ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(path, action); } [Fact] public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_WorksWithNonDiskBasedFiles(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_WorksWithNonDiskBasedFiles(action); } [Fact] public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile() { - var actionType = "ActionContext"; - var action = new Func(async (result, context) => await result.ExecuteResultAsync((ActionContext)context)); + var action = new Func(async (result, context) => await result.ExecuteResultAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile(action); } } } diff --git a/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs b/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs index b9bfb75aba2e..04a1f14037d4 100644 --- a/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs +++ b/src/Mvc/Mvc.Core/test/VirtualFileResultTest.cs @@ -17,44 +17,38 @@ public class VirtualFileResultTest [InlineData(8, null, "ResultTestFile contents¡", 25)] public async Task WriteFileAsync_WritesRangeRequested(long? start, long? end, string expectedString, long contentLength) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseVirtualFileResultTest.WriteFileAsync_WritesRangeRequested( start, end, expectedString, contentLength, - actionType, action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange(action); } [Fact] public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest - .WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored(action); } [Fact] public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored(action); } [Theory] @@ -63,11 +57,9 @@ public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored() [InlineData("bytes = 1-4, 5-11")] public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest - .WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(rangeString, action); } [Theory] @@ -75,49 +67,43 @@ await BaseVirtualFileResultTest [InlineData("bytes = -0")] public async Task WriteFileAsync_RangeRequestedNotSatisfiable(string rangeString) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest - .WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequestedNotSatisfiable(rangeString, action); } [Fact] public async Task WriteFileAsync_RangeRequested_PreconditionFailed() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_PreconditionFailed(action); } [Fact] public async Task WriteFileAsync_RangeRequested_NotModified() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_NotModified(actionType, action); + await BaseVirtualFileResultTest.WriteFileAsync_RangeRequested_NotModified(action); } [Fact] public async Task ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent(actionType, action); + .ExecuteResultAsync_FallsBackToWebRootFileProvider_IfNoFileProviderIsPresent(action); } [Fact] public async Task ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(actionType, action); + .ExecuteResultAsync_CallsSendFileAsync_IfIHttpSendFilePresent(action); } [Theory] @@ -127,34 +113,30 @@ await BaseVirtualFileResultTest [InlineData(8, null, "ResultTestFile contents¡", 25)] public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, string expectedString, long contentLength) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseVirtualFileResultTest.ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent( start, end, expectedString, contentLength, - actionType, action); } [Fact] public async Task ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_SetsSuppliedContentTypeAndEncoding(action); } [Fact] public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_ReturnsFileContentsForRelativePaths(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_ReturnsFileContentsForRelativePaths(action); } [Theory] @@ -166,11 +148,10 @@ public async Task ExecuteResultAsync_ReturnsFileContentsForRelativePaths() [InlineData(@"\\..//?><|""&@#\c:\..\? /..txt")] public async Task ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(string path) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(path, actionType, action); + .ExecuteResultAsync_ReturnsFiles_ForDifferentPaths(path, action); } [Theory] @@ -181,29 +162,26 @@ await BaseVirtualFileResultTest [InlineData(@"~~~~\\..//?>~<|""&@#\c:\..\? /..txt~~~")] public async Task ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(string path) { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); await BaseVirtualFileResultTest - .ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(path, actionType, action); + .ExecuteResultAsync_TrimsTilde_BeforeInvokingFileProvider(path, action); } [Fact] public async Task ExecuteResultAsync_WorksWithNonDiskBasedFiles() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_WorksWithNonDiskBasedFiles(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_WorksWithNonDiskBasedFiles(action); } [Fact] public async Task ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile() { - var actionType = "HttpContext"; - var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync((HttpContext)context)); + var action = new Func(async (result, context) => await ((IResult)result).ExecuteAsync(context)); - await BaseVirtualFileResultTest.ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile(actionType, action); + await BaseVirtualFileResultTest.ExecuteResultAsync_ThrowsFileNotFound_IfFileProviderCanNotFindTheFile(action); } } }