using System.Reflection; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Web.Common.Controllers; using Umbraco.Cms.Web.Common.Routing; using Umbraco.Cms.Web.Website.Controllers; using Umbraco.Cms.Web.Website.Routing; using Umbraco.Extensions; using static Umbraco.Cms.Core.Constants.Web.Routing; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing; [TestFixture] public class UmbracoRouteValueTransformerTests { private IOptions GetGlobalSettings() => Options.Create(new GlobalSettings()); private UmbracoRouteValueTransformer GetTransformerWithRunState( IUmbracoContextAccessor ctx, IRoutableDocumentFilter filter = null, IPublishedRouter router = null, IUmbracoRouteValuesFactory routeValuesFactory = null, IDocumentUrlService documentUrlService = null) => GetTransformer(ctx, Mock.Of(x => x.Level == RuntimeLevel.Run), filter, router, routeValuesFactory, documentUrlService); private UmbracoRouteValueTransformer GetTransformer( IUmbracoContextAccessor ctx, IRuntimeState state, IRoutableDocumentFilter filter = null, IPublishedRouter router = null, IUmbracoRouteValuesFactory routeValuesFactory = null, IDocumentUrlService documentUrlService = null) { var publicAccessRequestHandler = new Mock(); publicAccessRequestHandler.Setup(x => x.RewriteForPublishedContentAccessAsync(It.IsAny(), It.IsAny())) .Returns((HttpContext ctx, UmbracoRouteValues routeVals) => Task.FromResult(routeVals)); var umbracoVirtualPageRoute = new Mock(); umbracoVirtualPageRoute.Setup(x => x.SetupVirtualPageRoute(It.IsAny())); var transformer = new UmbracoRouteValueTransformer( new NullLogger(), ctx, router ?? Mock.Of(), state, routeValuesFactory ?? Mock.Of(), filter ?? Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == true), Mock.Of(), Mock.Of(), publicAccessRequestHandler.Object, Mock.Of(), Mock.Of>(), documentUrlService ?? Mock.Of(x => x.HasAny() == true)); return transformer; } private IUmbracoContext GetUmbracoContext(bool hasContent) { var publishedContent = Mock.Of(x => x.HasAny() == hasContent); var uri = new Uri("http://example.com"); var umbracoContext = Mock.Of(x => x.Content == publishedContent && x.OriginalRequestUrl == uri && x.CleanedUmbracoUrl == uri); return umbracoContext; } private UmbracoRouteValues GetRouteValues(IPublishedRequest request) => new( request, new ControllerActionDescriptor { ControllerTypeInfo = typeof(TestController).GetTypeInfo(), ControllerName = ControllerExtensions.GetControllerName(), }); private IUmbracoRouteValuesFactory GetRouteValuesFactory(IPublishedRequest request) => Mock.Of(x => x.CreateAsync(It.IsAny(), It.IsAny()) == Task.FromResult(GetRouteValues(request))); private IPublishedRouter GetRouter(IPublishedRequest request) => Mock.Of(x => x.RouteRequestAsync(It.IsAny(), It.IsAny()) == Task.FromResult(request)); [Test] public async Task Null_When_Runtime_Level_Not_Run() { var transformer = GetTransformer( Mock.Of(), Mock.Of()); var result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); Assert.IsNull(result); } [Test] public async Task Null_When_No_Umbraco_Context() { var transformer = GetTransformerWithRunState( Mock.Of()); var result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); Assert.IsNull(result); } [Test] public async Task Null_When_Not_Document_Request() { var umbracoContext = Mock.Of(); var transformer = GetTransformerWithRunState( Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == false)); var result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); Assert.IsNull(result); } [Test] public async Task NoContentController_Values_When_No_Content() { var umbracoContext = GetUmbracoContext(false); var transformer = GetTransformerWithRunState( Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), null, null, null, Mock.Of(x => x.HasAny() == false)); var result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); Assert.AreEqual(2, result.Count); Assert.AreEqual(ControllerExtensions.GetControllerName(), result[ControllerToken]); Assert.AreEqual(nameof(RenderNoContentController.Index), result[ActionToken]); } [Test] public async Task Assigns_PublishedRequest_To_UmbracoContext() { var umbracoContext = GetUmbracoContext(true); var request = Mock.Of(); var transformer = GetTransformerWithRunState( Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), router: GetRouter(request), routeValuesFactory: GetRouteValuesFactory(request)); await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); Assert.AreEqual(request, umbracoContext.PublishedRequest); } [Test] public async Task Null_When_No_Content_On_PublishedRequest() { var umbracoContext = GetUmbracoContext(true); var request = Mock.Of(x => x.PublishedContent == null); var transformer = GetTransformerWithRunState( Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), router: GetRouter(request), routeValuesFactory: GetRouteValuesFactory(request)); var httpContext = new DefaultHttpContext(); var result = await transformer.TransformAsync(httpContext, new RouteValueDictionary()); Assert.IsNull(result); var routeVals = httpContext.Features.Get(); Assert.AreEqual(routeVals.PublishedRequest.GetRouteResult(), UmbracoRouteResult.NotFound); } [Test] public async Task Assigns_UmbracoRouteValues_To_HttpContext_Feature() { var umbracoContext = GetUmbracoContext(true); var request = Mock.Of(x => x.PublishedContent == Mock.Of()); var transformer = GetTransformerWithRunState( Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), router: GetRouter(request), routeValuesFactory: GetRouteValuesFactory(request)); var httpContext = new DefaultHttpContext(); await transformer.TransformAsync(httpContext, new RouteValueDictionary()); var routeVals = httpContext.Features.Get(); Assert.IsNotNull(routeVals); Assert.AreEqual(routeVals.PublishedRequest, umbracoContext.PublishedRequest); } [Test] public async Task Assigns_Values_To_RouteValueDictionary_When_Content() { var umbracoContext = GetUmbracoContext(true); var request = Mock.Of(x => x.PublishedContent == Mock.Of()); var routeValues = GetRouteValues(request); var transformer = GetTransformerWithRunState( Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), router: GetRouter(request), routeValuesFactory: GetRouteValuesFactory(request)); var result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); Assert.AreEqual(routeValues.ControllerName, result[ControllerToken]); Assert.AreEqual(routeValues.ActionName, result[ActionToken]); } [Test] public async Task Returns_Null_RouteValueDictionary_When_No_Content() { var umbracoContext = GetUmbracoContext(true); var request = Mock.Of(x => x.PublishedContent == null); GetRouteValues(request); var transformer = GetTransformerWithRunState( Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), router: GetRouter(request), routeValuesFactory: GetRouteValuesFactory(request)); var result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); Assert.IsNull(result); } private class TestController : RenderController { public TestController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, compositeViewEngine, umbracoContextAccessor) { } } }