File: Infrastructure\DefaultPageLoaderTest.cs
Web Access
Project: src\src\Mvc\Mvc.RazorPages\test\Microsoft.AspNetCore.Mvc.RazorPages.Test.csproj (Microsoft.AspNetCore.Mvc.RazorPages.Test)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Razor.Hosting;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.Options;
using Moq;
 
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
 
public class DefaultPageLoaderTest
{
    private readonly IOptions<RazorPagesOptions> RazorPagesOptions = Options.Create(new RazorPagesOptions { Conventions = new PageConventionCollection(Mock.Of<IServiceProvider>()) });
    private readonly IActionDescriptorCollectionProvider ActionDescriptorCollectionProvider;
 
    public DefaultPageLoaderTest()
    {
        var actionDescriptors = new ActionDescriptorCollection(Array.Empty<ActionDescriptor>(), 1);
        ActionDescriptorCollectionProvider = Mock.Of<IActionDescriptorCollectionProvider>(v => v.ActionDescriptors == actionDescriptors);
    }
 
    [Fact]
    public async Task LoadAsync_InvokesApplicationModelProviders()
    {
        // Arrange
        var descriptor = new PageActionDescriptor();
 
        var compilerProvider = GetCompilerProvider();
 
        var mvcOptions = Options.Create(new MvcOptions());
        var endpointFactory = new ActionEndpointFactory(Mock.Of<RoutePatternTransformer>(), Enumerable.Empty<IRequestDelegateFactory>(), Mock.Of<IServiceProvider>());
 
        var provider1 = new Mock<IPageApplicationModelProvider>();
        var provider2 = new Mock<IPageApplicationModelProvider>();
 
        var sequence = 0;
        var pageApplicationModel1 = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
        var pageApplicationModel2 = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
 
        provider1.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(0, sequence++);
                Assert.Null(c.PageApplicationModel);
                c.PageApplicationModel = pageApplicationModel1;
            })
            .Verifiable();
 
        provider2.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(1, sequence++);
                Assert.Same(pageApplicationModel1, c.PageApplicationModel);
                c.PageApplicationModel = pageApplicationModel2;
            })
            .Verifiable();
 
        provider1.Setup(p => p.OnProvidersExecuted(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(3, sequence++);
                Assert.Same(pageApplicationModel2, c.PageApplicationModel);
            })
            .Verifiable();
 
        provider2.Setup(p => p.OnProvidersExecuted(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(2, sequence++);
                Assert.Same(pageApplicationModel2, c.PageApplicationModel);
            })
            .Verifiable();
 
        var providers = new[]
        {
                provider1.Object, provider2.Object
            };
 
        var loader = new DefaultPageLoader(
            providers,
            compilerProvider,
            endpointFactory,
            RazorPagesOptions,
            mvcOptions);
 
        // Act
        var result = await loader.LoadAsync(new PageActionDescriptor(), EndpointMetadataCollection.Empty);
 
        // Assert
        provider1.Verify();
        provider2.Verify();
    }
 
    [Fact]
    public async Task LoadAsync_CreatesEndpoint_WithRoute()
    {
        // Arrange
        var descriptor = new PageActionDescriptor()
        {
            AttributeRouteInfo = new AttributeRouteInfo()
            {
                Template = "/test",
            },
        };
 
        var transformer = new Mock<RoutePatternTransformer>();
        transformer
            .Setup(t => t.SubstituteRequiredValues(It.IsAny<RoutePattern>(), It.IsAny<object>()))
            .Returns<RoutePattern, object>((p, v) => p);
 
        var compilerProvider = GetCompilerProvider();
 
        var mvcOptions = Options.Create(new MvcOptions());
        var endpointFactory = new ActionEndpointFactory(transformer.Object, Enumerable.Empty<IRequestDelegateFactory>(), Mock.Of<IServiceProvider>());
 
        var provider = new Mock<IPageApplicationModelProvider>();
 
        var pageApplicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
 
        provider.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Null(c.PageApplicationModel);
                c.PageApplicationModel = pageApplicationModel;
            })
            .Verifiable();
 
        var providers = new[]
        {
                provider.Object,
            };
 
        var loader = new DefaultPageLoader(
            providers,
            compilerProvider,
            endpointFactory,
            RazorPagesOptions,
            mvcOptions);
 
        // Act
        var result = await loader.LoadAsync(descriptor, EndpointMetadataCollection.Empty);
 
        // Assert
        Assert.NotNull(result.Endpoint);
    }
 
    [Fact]
    public async Task LoadAsync_InvokesApplicationModelProviders_WithTheRightOrder()
    {
        // Arrange
        var descriptor = new PageActionDescriptor();
        var compilerProvider = GetCompilerProvider();
        var mvcOptions = Options.Create(new MvcOptions());
        var endpointFactory = new ActionEndpointFactory(Mock.Of<RoutePatternTransformer>(), Enumerable.Empty<IRequestDelegateFactory>(), Mock.Of<IServiceProvider>());
 
        var provider1 = new Mock<IPageApplicationModelProvider>();
        provider1.SetupGet(p => p.Order).Returns(10);
        var provider2 = new Mock<IPageApplicationModelProvider>();
        provider2.SetupGet(p => p.Order).Returns(-5);
 
        var sequence = 0;
        provider1.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(1, sequence++);
                c.PageApplicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
            })
            .Verifiable();
 
        provider2.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(0, sequence++);
            })
            .Verifiable();
 
        provider1.Setup(p => p.OnProvidersExecuted(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(2, sequence++);
            })
            .Verifiable();
 
        provider2.Setup(p => p.OnProvidersExecuted(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Equal(3, sequence++);
            })
            .Verifiable();
 
        var providers = new[]
        {
                provider1.Object, provider2.Object
            };
 
        var loader = new DefaultPageLoader(
            providers,
            compilerProvider,
            endpointFactory,
            RazorPagesOptions,
            mvcOptions);
 
        // Act
        var result = await loader.LoadAsync(new PageActionDescriptor(), EndpointMetadataCollection.Empty);
 
        // Assert
        provider1.Verify();
        provider2.Verify();
    }
 
    [Fact]
    public async Task LoadAsync_CachesResults()
    {
        // Arrange
        var descriptor = new PageActionDescriptor()
        {
            AttributeRouteInfo = new AttributeRouteInfo()
            {
                Template = "/test",
            },
        };
 
        var transformer = new Mock<RoutePatternTransformer>();
        transformer
            .Setup(t => t.SubstituteRequiredValues(It.IsAny<RoutePattern>(), It.IsAny<object>()))
            .Returns<RoutePattern, object>((p, v) => p);
 
        var compilerProvider = GetCompilerProvider();
 
        var mvcOptions = Options.Create(new MvcOptions());
        var endpointFactory = new ActionEndpointFactory(transformer.Object, Enumerable.Empty<IRequestDelegateFactory>(), Mock.Of<IServiceProvider>());
 
        var provider = new Mock<IPageApplicationModelProvider>();
 
        var pageApplicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
 
        provider.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Null(c.PageApplicationModel);
                c.PageApplicationModel = pageApplicationModel;
            })
            .Verifiable();
 
        var providers = new[]
        {
                provider.Object,
            };
 
        var loader = new DefaultPageLoader(
            providers,
            compilerProvider,
            endpointFactory,
            RazorPagesOptions,
            mvcOptions);
 
        // Act
        var result1 = await loader.LoadAsync(descriptor, EndpointMetadataCollection.Empty);
        var result2 = await loader.LoadAsync(descriptor, EndpointMetadataCollection.Empty);
 
        // Assert
        Assert.Same(result1, result2);
    }
 
    [Fact]
    public async Task LoadAsync_IsUniquePerPageDescriptor()
    {
        // Arrange
        var descriptor = new PageActionDescriptor()
        {
            AttributeRouteInfo = new AttributeRouteInfo()
            {
                Template = "/test",
            },
        };
 
        var descriptor2 = new PageActionDescriptor()
        {
            AttributeRouteInfo = new AttributeRouteInfo()
            {
                Template = "/test",
            },
        };
 
        var transformer = new Mock<RoutePatternTransformer>();
        transformer
            .Setup(t => t.SubstituteRequiredValues(It.IsAny<RoutePattern>(), It.IsAny<object>()))
            .Returns<RoutePattern, object>((p, v) => p);
 
        var compilerProvider = GetCompilerProvider();
 
        var mvcOptions = Options.Create(new MvcOptions());
        var endpointFactory = new ActionEndpointFactory(transformer.Object, Enumerable.Empty<IRequestDelegateFactory>(), Mock.Of<IServiceProvider>());
 
        var provider = new Mock<IPageApplicationModelProvider>();
 
        provider.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
            .Callback((PageApplicationModelProviderContext c) =>
            {
                Assert.Null(c.PageApplicationModel);
                c.PageApplicationModel = new PageApplicationModel(c.ActionDescriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
            })
            .Verifiable();
 
        var providers = new[]
        {
                provider.Object,
            };
 
        var loader = new DefaultPageLoader(
            providers,
            compilerProvider,
            endpointFactory,
            RazorPagesOptions,
            mvcOptions);
 
        // Act
        var result1 = await loader.LoadAsync(descriptor, EndpointMetadataCollection.Empty);
        var result2 = await loader.LoadAsync(descriptor2, EndpointMetadataCollection.Empty);
 
        // Assert
        Assert.NotSame(result1, result2);
    }
 
    [Fact]
    public async Task LoadAsync_CompiledPageActionDescriptor_ReturnsSelf()
    {
        // Arrange
        var mvcOptions = Options.Create(new MvcOptions());
        var endpointFactory = new ActionEndpointFactory(Mock.Of<RoutePatternTransformer>(), Enumerable.Empty<IRequestDelegateFactory>(), Mock.Of<IServiceProvider>());
        var loader = new DefaultPageLoader(
            new[] { Mock.Of<IPageApplicationModelProvider>() },
            Mock.Of<IViewCompilerProvider>(),
            endpointFactory,
            RazorPagesOptions,
            mvcOptions);
        var pageDescriptor = new CompiledPageActionDescriptor();
 
        // Act
        var result1 = await loader.LoadAsync(pageDescriptor, new EndpointMetadataCollection());
        var result2 = await loader.LoadAsync(pageDescriptor, new EndpointMetadataCollection());
 
        // Assert
        Assert.Same(pageDescriptor, result1);
        Assert.Same(pageDescriptor, result2);
    }
 
    private static IViewCompilerProvider GetCompilerProvider()
    {
        var compiledItem = TestRazorCompiledItem.CreateForView(typeof(object), "/Views/Index.cshtml");
        var descriptor = new CompiledViewDescriptor(compiledItem);
        var compiler = new Mock<IViewCompiler>();
        compiler.Setup(c => c.CompileAsync(It.IsAny<string>()))
            .ReturnsAsync(descriptor);
        var compilerProvider = new Mock<IViewCompilerProvider>();
        compilerProvider.Setup(p => p.GetCompiler())
            .Returns(compiler.Object);
        return compilerProvider.Object;
    }
}