File: LocalRedirectResultTests.cs
Web Access
Project: src\src\Http\Http.Results\test\Microsoft.AspNetCore.Http.Results.Tests.csproj (Microsoft.AspNetCore.Http.Results.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
 
namespace Microsoft.AspNetCore.Http.HttpResults;
 
public class LocalRedirectResultTests
{
    [Fact]
    public void Constructor_WithParameterUrl_SetsResultUrlAndNotPermanentOrPreserveMethod()
    {
        // Arrange
        var url = "/test/url";
 
        // Act
        var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, false, false);
 
        // Assert
        Assert.False(result.PreserveMethod);
        Assert.False(result.Permanent);
        Assert.Same(url, result.Url);
    }
 
    [Fact]
    public void Constructor_WithParameterUrlAndPermanent_SetsResultUrlAndPermanentNotPreserveMethod()
    {
        // Arrange
        var url = "/test/url";
 
        // Act
        var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: false);
 
        // Assert
        Assert.False(result.PreserveMethod);
        Assert.True(result.Permanent);
        Assert.Same(url, result.Url);
    }
 
    [Fact]
    public void Constructor_WithParameterUrlAndPermanent_SetsResultUrlPermanentAndPreserveMethod()
    {
        // Arrange
        var url = "/test/url";
 
        // Act
        var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: true);
 
        // Assert
        Assert.True(result.PreserveMethod);
        Assert.True(result.Permanent);
        Assert.Same(url, result.Url);
    }
 
    [Fact]
    public async Task Execute_ReturnsExpectedValues()
    {
        // Arrange
        var appRoot = "/";
        var contentPath = "~/Home/About";
        var expectedPath = "/Home/About";
 
        var httpContext = GetHttpContext(appRoot);
        var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false);
 
        // Act
        await result.ExecuteAsync(httpContext);
 
        // Assert
        Assert.Equal(expectedPath, httpContext.Response.Headers.Location.ToString());
        Assert.Equal(StatusCodes.Status302Found, httpContext.Response.StatusCode);
    }
 
    [Theory]
    [InlineData("", "//")]
    [InlineData("", "/\\")]
    [InlineData("", "//foo")]
    [InlineData("", "/\\foo")]
    [InlineData("", "Home/About")]
    [InlineData("/myapproot", "http://www.example.com")]
    public async Task Execute_Throws_ForNonLocalUrl(
        string appRoot,
        string contentPath)
    {
        // Arrange
        var httpContext = GetHttpContext(appRoot);
        var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false);
 
        // Act & Assert
        var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => result.ExecuteAsync(httpContext));
        Assert.Equal(
            "The supplied URL is not local. A URL with an absolute path is considered local if it does not " +
            "have a host/authority part. URLs using virtual paths ('~/') are also local.",
            exception.Message);
    }
 
    [Theory]
    [InlineData("", "~//")]
    [InlineData("", "~/\\")]
    [InlineData("", "~//foo")]
    [InlineData("", "~/\\foo")]
    public async Task Execute_Throws_ForNonLocalUrlTilde(
        string appRoot,
        string contentPath)
    {
        // Arrange
        var httpContext = GetHttpContext(appRoot);
        var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false);
 
        // Act & Assert
        var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => result.ExecuteAsync(httpContext));
        Assert.Equal(
            "The supplied URL is not local. A URL with an absolute path is considered local if it does not " +
            "have a host/authority part. URLs using virtual paths ('~/') are also local.",
            exception.Message);
    }
 
    private static IServiceProvider GetServiceProvider()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddTransient(typeof(ILogger<>), typeof(NullLogger<>));
        serviceCollection.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
        return serviceCollection.BuildServiceProvider();
    }
 
    private static HttpContext GetHttpContext(string appRoot)
    {
        var httpContext = new DefaultHttpContext();
        httpContext.RequestServices = GetServiceProvider();
        httpContext.Request.PathBase = new PathString(appRoot);
        return httpContext;
    }
}