// 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 Microsoft.AspNetCore.Routing.Constraints; using Microsoft.Extensions.DependencyInjection; using System.Collections.Generic; using System.Linq; using Xunit; namespace Microsoft.AspNetCore.Routing.Patterns { public class DefaultRoutePatternTransformerTest { public DefaultRoutePatternTransformerTest() { var services = new ServiceCollection(); services.AddRouting(); services.AddOptions(); Transformer = services.BuildServiceProvider().GetRequiredService(); } public RoutePatternTransformer Transformer { get; } [Fact] public void SubstituteRequiredValues_CanAcceptNullForAnyKey() { // Arrange var template = "{controller=Home}/{action=Index}/{id?}"; var defaults = new { }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { a = (string)null, b = "", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("a", null), kvp), kvp => Assert.Equal(new KeyValuePair("b", string.Empty), kvp)); } [Fact] public void SubstituteRequiredValues_RejectsNullForParameter() { // Arrange var template = "{controller=Home}/{action=Index}/{id?}"; var defaults = new { }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = string.Empty, }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Null(actual); } [Fact] public void SubstituteRequiredValues_RejectsNullForOutOfLineDefault() { // Arrange var template = "{controller=Home}/{action=Index}/{id?}"; var defaults = new { area = "Admin" }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { area = string.Empty, }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Null(actual); } [Fact] public void SubstituteRequiredValues_CanAcceptValueForParameter() { // Arrange var template = "{controller}/{action}/{id?}"; var defaults = new { }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); } [Fact] public void SubstituteRequiredValues_CanAcceptValueForParameter_WithSameDefault() { // Arrange var template = "{controller=Home}/{action=Index}/{id?}"; var defaults = new { }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); // We should not need to rewrite anything in this case. Assert.Same(actual.Defaults, original.Defaults); Assert.Same(actual.Parameters, original.Parameters); Assert.Same(actual.PathSegments, original.PathSegments); } [Fact] public void SubstituteRequiredValues_CanAcceptValueForParameter_WithDifferentDefault() { // Arrange var template = "{controller=Blog}/{action=ReadPost}/{id?}"; var defaults = new { area = "Admin", }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { area = "Admin", controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("area", "Admin"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); // We should not need to rewrite anything in this case. Assert.NotSame(actual.Defaults, original.Defaults); Assert.NotSame(actual.Parameters, original.Parameters); Assert.NotSame(actual.PathSegments, original.PathSegments); // other defaults were wiped out Assert.Equal(new KeyValuePair("area", "Admin"), Assert.Single(actual.Defaults)); Assert.Null(actual.GetParameter("controller").Default); Assert.False(actual.Defaults.ContainsKey("controller")); Assert.Null(actual.GetParameter("action").Default); Assert.False(actual.Defaults.ContainsKey("action")); } [Fact] public void SubstituteRequiredValues_CanAcceptValueForParameter_WithMatchingConstraint() { // Arrange var template = "{controller}/{action}/{id?}"; var defaults = new { }; var policies = new { controller = "Home", action = new RegexRouteConstraint("Index"), }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); } [Fact] public void SubstituteRequiredValues_CanRejectValueForParameter_WithNonMatchingConstraint() { // Arrange var template = "{controller}/{action}/{id?}"; var defaults = new { }; var policies = new { controller = "Home", action = new RegexRouteConstraint("Index"), }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Blog", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Null(actual); } [Fact] public void SubstituteRequiredValues_CanAcceptValueForDefault_WithSameValue() { // Arrange var template = "Home/Index/{id?}"; var defaults = new { controller = "Home", action = "Index", }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); } [Fact] public void SubstituteRequiredValues_CanRejectValueForDefault_WithDifferentValue() { // Arrange var template = "Home/Index/{id?}"; var defaults = new { controller = "Home", action = "Index", }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Blog", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Null(actual); } [Fact] public void SubstituteRequiredValues_CanAcceptValueForDefault_WithSameValue_Null() { // Arrange var template = "Home/Index/{id?}"; var defaults = new { controller = (string)null, action = "", }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = string.Empty, action = (string)null, }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", null), kvp), kvp => Assert.Equal(new KeyValuePair("controller", ""), kvp)); } [Fact] public void SubstituteRequiredValues_CanAcceptValueForDefault_WithSameValue_WithMatchingConstraint() { // Arrange var template = "Home/Index/{id?}"; var defaults = new { controller = "Home", action = "Index", }; var policies = new { controller = "Home", }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); } [Fact] public void SubstituteRequiredValues_CanRejectValueForDefault_WithSameValue_WithNonMatchingConstraint() { // Arrange var template = "Home/Index/{id?}"; var defaults = new { controller = "Home", action = "Index", }; var policies = new { controller = "Home", }; var original = RoutePatternFactory.Parse(template, defaults, policies); var requiredValues = new { controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); } [Fact] public void SubstituteRequiredValues_CanMergeExistingRequiredValues() { // Arrange var template = "Home/Index/{id?}"; var defaults = new { area = "Admin", controller = "Home", action = "Index", }; var policies = new { }; var original = RoutePatternFactory.Parse(template, defaults, policies, new { area = "Admin", controller = "Home", }); var requiredValues = new { controller = "Home", action = "Index", }; // Act var actual = Transformer.SubstituteRequiredValues(original, requiredValues); // Assert Assert.Collection( actual.RequiredValues.OrderBy(kvp => kvp.Key), kvp => Assert.Equal(new KeyValuePair("action", "Index"), kvp), kvp => Assert.Equal(new KeyValuePair("area", "Admin"), kvp), kvp => Assert.Equal(new KeyValuePair("controller", "Home"), kvp)); } } }