diff options
Diffstat (limited to 'src/Http/Routing/test/UnitTests/RouteCollectionTest.cs')
-rw-r--r-- | src/Http/Routing/test/UnitTests/RouteCollectionTest.cs | 1099 |
1 files changed, 549 insertions, 550 deletions
diff --git a/src/Http/Routing/test/UnitTests/RouteCollectionTest.cs b/src/Http/Routing/test/UnitTests/RouteCollectionTest.cs index 8082af30f0..62346d6af9 100644 --- a/src/Http/Routing/test/UnitTests/RouteCollectionTest.cs +++ b/src/Http/Routing/test/UnitTests/RouteCollectionTest.cs @@ -15,349 +15,349 @@ using Microsoft.Extensions.Options; using Moq; using Xunit; -namespace Microsoft.AspNetCore.Routing +namespace Microsoft.AspNetCore.Routing; + +public class RouteCollectionTest { - public class RouteCollectionTest + private static readonly RequestDelegate NullHandler = (c) => Task.CompletedTask; + + [Theory] + [InlineData(@"Home/Index/23", "/home/index/23", true, false)] + [InlineData(@"Home/Index/23", "/Home/Index/23", false, false)] + [InlineData(@"Home/Index/23", "/home/index/23/", true, true)] + [InlineData(@"Home/Index/23", "/Home/Index/23/", false, true)] + [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23/?Param1=ABC&Param2=Xyz", false, true)] + [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23?Param1=ABC&Param2=Xyz", false, false)] + [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/home/index/23/?Param1=ABC&Param2=Xyz", true, true)] + [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/Home/Index/23/#Param1=ABC&Param2=Xyz", false, true)] + [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/home/index/23#Param1=ABC&Param2=Xyz", true, false)] + [InlineData(@"Home/Index/23/?Param1=ABC&Param2=Xyz", "/home/index/23/?Param1=ABC&Param2=Xyz", true, true)] + [InlineData(@"Home/Index/23/#Param1=ABC&Param2=Xyz", "/home/index/23/#Param1=ABC&Param2=Xyz", true, false)] + public void GetVirtualPath_CanLowerCaseUrls_And_AppendTrailingSlash_BasedOnOptions( + string returnUrl, + string expectedUrl, + bool lowercaseUrls, + bool appendTrailingSlash) { - private static readonly RequestDelegate NullHandler = (c) => Task.CompletedTask; - - [Theory] - [InlineData(@"Home/Index/23", "/home/index/23", true, false)] - [InlineData(@"Home/Index/23", "/Home/Index/23", false, false)] - [InlineData(@"Home/Index/23", "/home/index/23/", true, true)] - [InlineData(@"Home/Index/23", "/Home/Index/23/", false, true)] - [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23/?Param1=ABC&Param2=Xyz", false, true)] - [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23?Param1=ABC&Param2=Xyz", false, false)] - [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/home/index/23/?Param1=ABC&Param2=Xyz", true, true)] - [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/Home/Index/23/#Param1=ABC&Param2=Xyz", false, true)] - [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/home/index/23#Param1=ABC&Param2=Xyz", true, false)] - [InlineData(@"Home/Index/23/?Param1=ABC&Param2=Xyz", "/home/index/23/?Param1=ABC&Param2=Xyz", true, true)] - [InlineData(@"Home/Index/23/#Param1=ABC&Param2=Xyz", "/home/index/23/#Param1=ABC&Param2=Xyz", true, false)] - public void GetVirtualPath_CanLowerCaseUrls_And_AppendTrailingSlash_BasedOnOptions( - string returnUrl, - string expectedUrl, - bool lowercaseUrls, - bool appendTrailingSlash) - { - // Arrange - var target = new Mock<IRouter>(MockBehavior.Strict); - target - .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) - .Returns(new VirtualPathData(target.Object, returnUrl)); - - var routeCollection = new RouteCollection(); - routeCollection.Add(target.Object); - var virtualPathContext = CreateVirtualPathContext( - options: GetRouteOptions( - lowerCaseUrls: lowercaseUrls, - appendTrailingSlash: appendTrailingSlash)); - - // Act - var pathData = routeCollection.GetVirtualPath(virtualPathContext); - - // Assert - Assert.Equal(expectedUrl, pathData.VirtualPath); - Assert.Same(target.Object, pathData.Router); - Assert.Empty(pathData.DataTokens); - } + // Arrange + var target = new Mock<IRouter>(MockBehavior.Strict); + target + .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) + .Returns(new VirtualPathData(target.Object, returnUrl)); + + var routeCollection = new RouteCollection(); + routeCollection.Add(target.Object); + var virtualPathContext = CreateVirtualPathContext( + options: GetRouteOptions( + lowerCaseUrls: lowercaseUrls, + appendTrailingSlash: appendTrailingSlash)); + + // Act + var pathData = routeCollection.GetVirtualPath(virtualPathContext); + + // Assert + Assert.Equal(expectedUrl, pathData.VirtualPath); + Assert.Same(target.Object, pathData.Router); + Assert.Empty(pathData.DataTokens); + } - [Theory] - [InlineData(@"\u0130", @"/\u0130", true)] - [InlineData(@"\u0049", @"/\u0049", true)] - [InlineData(@"�ino", @"/�ino", true)] - public void GetVirtualPath_DoesntLowerCaseUrls_Invariant( - string returnUrl, - string lowercaseUrl, - bool lowercaseUrls) - { - // Arrange - var target = new Mock<IRouter>(MockBehavior.Strict); - target - .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) - .Returns(new VirtualPathData(target.Object, returnUrl)); - - var routeCollection = new RouteCollection(); - routeCollection.Add(target.Object); - var virtualPathContext = CreateVirtualPathContext(options: GetRouteOptions(lowercaseUrls)); - - // Act - var pathData = routeCollection.GetVirtualPath(virtualPathContext); - - // Assert - Assert.Equal(lowercaseUrl, pathData.VirtualPath); - Assert.Same(target.Object, pathData.Router); - Assert.Empty(pathData.DataTokens); - } + [Theory] + [InlineData(@"\u0130", @"/\u0130", true)] + [InlineData(@"\u0049", @"/\u0049", true)] + [InlineData(@"�ino", @"/�ino", true)] + public void GetVirtualPath_DoesntLowerCaseUrls_Invariant( + string returnUrl, + string lowercaseUrl, + bool lowercaseUrls) + { + // Arrange + var target = new Mock<IRouter>(MockBehavior.Strict); + target + .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) + .Returns(new VirtualPathData(target.Object, returnUrl)); + + var routeCollection = new RouteCollection(); + routeCollection.Add(target.Object); + var virtualPathContext = CreateVirtualPathContext(options: GetRouteOptions(lowercaseUrls)); + + // Act + var pathData = routeCollection.GetVirtualPath(virtualPathContext); + + // Assert + Assert.Equal(lowercaseUrl, pathData.VirtualPath); + Assert.Same(target.Object, pathData.Router); + Assert.Empty(pathData.DataTokens); + } - [Theory] - [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23?Param1=ABC&Param2=Xyz", false, true, false)] - [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23?Param1=ABC&Param2=Xyz", false, false, false)] - [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/home/index/23/?param1=abc¶m2=xyz", true, true, true)] - [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/Home/Index/23/#Param1=ABC&Param2=Xyz", false, true, true)] - [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/home/index/23#Param1=ABC&Param2=Xyz", true, false, false)] - [InlineData(@"Home/Index/23/?Param1=ABC&Param2=Xyz", "/home/index/23/?param1=abc¶m2=xyz", true, true, true)] - [InlineData(@"Home/Index/23/#Param1=ABC&Param2=Xyz", "/home/index/23/#Param1=ABC&Param2=Xyz", true, false, true)] - [InlineData(@"Home/Index/23/#Param1=ABC&Param2=Xyz", "/home/index/23/#param1=abc¶m2=xyz", true, true, true)] - public void GetVirtualPath_CanLowerCaseUrls_QueryStrings_BasedOnOptions( - string returnUrl, - string expectedUrl, - bool lowercaseUrls, - bool lowercaseQueryStrings, bool appendTrailingSlash) - { - // Arrange - var target = new Mock<IRouter>(MockBehavior.Strict); - target - .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) - .Returns(new VirtualPathData(target.Object, returnUrl)); - - var routeCollection = new RouteCollection(); - routeCollection.Add(target.Object); - var virtualPathContext = CreateVirtualPathContext( - options: GetRouteOptions( - lowerCaseUrls: lowercaseUrls, - lowercaseQueryStrings: lowercaseQueryStrings, - appendTrailingSlash: appendTrailingSlash)); - - // Act - var pathData = routeCollection.GetVirtualPath(virtualPathContext); - - // Assert - Assert.Equal(expectedUrl, pathData.VirtualPath); - Assert.Same(target.Object, pathData.Router); - Assert.Empty(pathData.DataTokens); - } + [Theory] + [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23?Param1=ABC&Param2=Xyz", false, true, false)] + [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/Home/Index/23?Param1=ABC&Param2=Xyz", false, false, false)] + [InlineData(@"Home/Index/23?Param1=ABC&Param2=Xyz", "/home/index/23/?param1=abc¶m2=xyz", true, true, true)] + [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/Home/Index/23/#Param1=ABC&Param2=Xyz", false, true, true)] + [InlineData(@"Home/Index/23#Param1=ABC&Param2=Xyz", "/home/index/23#Param1=ABC&Param2=Xyz", true, false, false)] + [InlineData(@"Home/Index/23/?Param1=ABC&Param2=Xyz", "/home/index/23/?param1=abc¶m2=xyz", true, true, true)] + [InlineData(@"Home/Index/23/#Param1=ABC&Param2=Xyz", "/home/index/23/#Param1=ABC&Param2=Xyz", true, false, true)] + [InlineData(@"Home/Index/23/#Param1=ABC&Param2=Xyz", "/home/index/23/#param1=abc¶m2=xyz", true, true, true)] + public void GetVirtualPath_CanLowerCaseUrls_QueryStrings_BasedOnOptions( + string returnUrl, + string expectedUrl, + bool lowercaseUrls, + bool lowercaseQueryStrings, bool appendTrailingSlash) + { + // Arrange + var target = new Mock<IRouter>(MockBehavior.Strict); + target + .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) + .Returns(new VirtualPathData(target.Object, returnUrl)); + + var routeCollection = new RouteCollection(); + routeCollection.Add(target.Object); + var virtualPathContext = CreateVirtualPathContext( + options: GetRouteOptions( + lowerCaseUrls: lowercaseUrls, + lowercaseQueryStrings: lowercaseQueryStrings, + appendTrailingSlash: appendTrailingSlash)); + + // Act + var pathData = routeCollection.GetVirtualPath(virtualPathContext); + + // Assert + Assert.Equal(expectedUrl, pathData.VirtualPath); + Assert.Same(target.Object, pathData.Router); + Assert.Empty(pathData.DataTokens); + } - [Theory] - [MemberData(nameof(DataTokensTestData))] - public void GetVirtualPath_ReturnsDataTokens(RouteValueDictionary dataTokens, string routerName) - { - // Arrange - var virtualPath = "/TestVirtualPath"; + [Theory] + [MemberData(nameof(DataTokensTestData))] + public void GetVirtualPath_ReturnsDataTokens(RouteValueDictionary dataTokens, string routerName) + { + // Arrange + var virtualPath = "/TestVirtualPath"; - var pathContextValues = new RouteValueDictionary { { "controller", virtualPath } }; + var pathContextValues = new RouteValueDictionary { { "controller", virtualPath } }; - var pathContext = CreateVirtualPathContext( - pathContextValues, - GetRouteOptions(), - routerName); + var pathContext = CreateVirtualPathContext( + pathContextValues, + GetRouteOptions(), + routerName); - var route = CreateTemplateRoute("{controller}", routerName, dataTokens); - var routeCollection = new RouteCollection(); - routeCollection.Add(route); + var route = CreateTemplateRoute("{controller}", routerName, dataTokens); + var routeCollection = new RouteCollection(); + routeCollection.Add(route); - var expectedDataTokens = dataTokens ?? new RouteValueDictionary(); + var expectedDataTokens = dataTokens ?? new RouteValueDictionary(); - // Act - var pathData = routeCollection.GetVirtualPath(pathContext); + // Act + var pathData = routeCollection.GetVirtualPath(pathContext); - // Assert - Assert.NotNull(pathData); - Assert.Same(route, pathData.Router); + // Assert + Assert.NotNull(pathData); + Assert.Same(route, pathData.Router); - Assert.Equal(virtualPath, pathData.VirtualPath); + Assert.Equal(virtualPath, pathData.VirtualPath); - Assert.Equal(expectedDataTokens.Count, pathData.DataTokens.Count); - foreach (var dataToken in expectedDataTokens) - { - Assert.True(pathData.DataTokens.ContainsKey(dataToken.Key)); - Assert.Equal(dataToken.Value, pathData.DataTokens[dataToken.Key]); - } + Assert.Equal(expectedDataTokens.Count, pathData.DataTokens.Count); + foreach (var dataToken in expectedDataTokens) + { + Assert.True(pathData.DataTokens.ContainsKey(dataToken.Key)); + Assert.Equal(dataToken.Value, pathData.DataTokens[dataToken.Key]); } + } - [Fact] - public async Task RouteAsync_FirstMatches() - { - // Arrange - var routes = new RouteCollection(); + [Fact] + public async Task RouteAsync_FirstMatches() + { + // Arrange + var routes = new RouteCollection(); - var route1 = CreateRoute(accept: true); - routes.Add(route1.Object); + var route1 = CreateRoute(accept: true); + routes.Add(route1.Object); - var route2 = CreateRoute(accept: false); - routes.Add(route2.Object); + var route2 = CreateRoute(accept: false); + routes.Add(route2.Object); - var context = CreateRouteContext("/Cool"); + var context = CreateRouteContext("/Cool"); - // Act - await routes.RouteAsync(context); + // Act + await routes.RouteAsync(context); - // Assert - route1.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); - route2.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(0)); - Assert.NotNull(context.Handler); + // Assert + route1.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); + route2.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(0)); + Assert.NotNull(context.Handler); - Assert.Equal(1, context.RouteData.Routers.Count); - Assert.Same(route1.Object, context.RouteData.Routers[0]); - } + Assert.Equal(1, context.RouteData.Routers.Count); + Assert.Same(route1.Object, context.RouteData.Routers[0]); + } - [Fact] - public async Task RouteAsync_SecondMatches() - { - // Arrange + [Fact] + public async Task RouteAsync_SecondMatches() + { + // Arrange - var routes = new RouteCollection(); - var route1 = CreateRoute(accept: false); - routes.Add(route1.Object); + var routes = new RouteCollection(); + var route1 = CreateRoute(accept: false); + routes.Add(route1.Object); - var route2 = CreateRoute(accept: true); - routes.Add(route2.Object); + var route2 = CreateRoute(accept: true); + routes.Add(route2.Object); - var context = CreateRouteContext("/Cool"); + var context = CreateRouteContext("/Cool"); - // Act - await routes.RouteAsync(context); + // Act + await routes.RouteAsync(context); - // Assert - route1.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); - route2.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); - Assert.NotNull(context.Handler); + // Assert + route1.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); + route2.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); + Assert.NotNull(context.Handler); - Assert.Equal(1, context.RouteData.Routers.Count); - Assert.Same(route2.Object, context.RouteData.Routers[0]); - } + Assert.Equal(1, context.RouteData.Routers.Count); + Assert.Same(route2.Object, context.RouteData.Routers[0]); + } - [Fact] - public async Task RouteAsync_NoMatch() - { - // Arrange - var routes = new RouteCollection(); - var route1 = CreateRoute(accept: false); - routes.Add(route1.Object); + [Fact] + public async Task RouteAsync_NoMatch() + { + // Arrange + var routes = new RouteCollection(); + var route1 = CreateRoute(accept: false); + routes.Add(route1.Object); - var route2 = CreateRoute(accept: false); - routes.Add(route2.Object); + var route2 = CreateRoute(accept: false); + routes.Add(route2.Object); - var context = CreateRouteContext("/Cool"); + var context = CreateRouteContext("/Cool"); - // Act - await routes.RouteAsync(context); + // Act + await routes.RouteAsync(context); - // Assert - route1.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); - route2.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); - Assert.Null(context.Handler); + // Assert + route1.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); + route2.Verify(e => e.RouteAsync(It.IsAny<RouteContext>()), Times.Exactly(1)); + Assert.Null(context.Handler); - Assert.Empty(context.RouteData.Routers); - } + Assert.Empty(context.RouteData.Routers); + } - [Theory] - [InlineData(false, "/RouteName")] - [InlineData(true, "/routename")] - public void NamedRouteTests_GetNamedRoute_ReturnsValue(bool lowercaseUrls, string expectedUrl) - { - // Arrange - var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", "RouteName", "Route3" }); - var virtualPathContext = CreateVirtualPathContext( - routeName: "RouteName", - options: GetRouteOptions(lowercaseUrls)); - - // Act - var pathData = routeCollection.GetVirtualPath(virtualPathContext); - - // Assert - Assert.Equal(expectedUrl, pathData.VirtualPath); - var namedRouter = Assert.IsAssignableFrom<INamedRouter>(pathData.Router); - Assert.Equal(virtualPathContext.RouteName, namedRouter.Name); - Assert.Empty(pathData.DataTokens); - } + [Theory] + [InlineData(false, "/RouteName")] + [InlineData(true, "/routename")] + public void NamedRouteTests_GetNamedRoute_ReturnsValue(bool lowercaseUrls, string expectedUrl) + { + // Arrange + var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", "RouteName", "Route3" }); + var virtualPathContext = CreateVirtualPathContext( + routeName: "RouteName", + options: GetRouteOptions(lowercaseUrls)); + + // Act + var pathData = routeCollection.GetVirtualPath(virtualPathContext); + + // Assert + Assert.Equal(expectedUrl, pathData.VirtualPath); + var namedRouter = Assert.IsAssignableFrom<INamedRouter>(pathData.Router); + Assert.Equal(virtualPathContext.RouteName, namedRouter.Name); + Assert.Empty(pathData.DataTokens); + } - [Fact] - public void NamedRouteTests_GetNamedRoute_RouteNotFound() - { - // Arrange - var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", "Route3" }); - var virtualPathContext = CreateVirtualPathContext("NonExistantRoute"); + [Fact] + public void NamedRouteTests_GetNamedRoute_RouteNotFound() + { + // Arrange + var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", "Route3" }); + var virtualPathContext = CreateVirtualPathContext("NonExistantRoute"); - // Act - var stringVirtualPath = routeCollection.GetVirtualPath(virtualPathContext); + // Act + var stringVirtualPath = routeCollection.GetVirtualPath(virtualPathContext); - // Assert - Assert.Null(stringVirtualPath); - } + // Assert + Assert.Null(stringVirtualPath); + } - [Fact] - public void NamedRouteTests_GetNamedRoute_AmbiguousRoutesInCollection_DoesNotThrowForUnambiguousRoute() - { - // Arrange - var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", "Route3", "Route4" }); + [Fact] + public void NamedRouteTests_GetNamedRoute_AmbiguousRoutesInCollection_DoesNotThrowForUnambiguousRoute() + { + // Arrange + var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", "Route3", "Route4" }); - // Add Duplicate route. - routeCollection.Add(CreateNamedRoute("Route3")); - var virtualPathContext = CreateVirtualPathContext(routeName: "Route1", options: GetRouteOptions(true)); + // Add Duplicate route. + routeCollection.Add(CreateNamedRoute("Route3")); + var virtualPathContext = CreateVirtualPathContext(routeName: "Route1", options: GetRouteOptions(true)); - // Act - var pathData = routeCollection.GetVirtualPath(virtualPathContext); + // Act + var pathData = routeCollection.GetVirtualPath(virtualPathContext); - // Assert - Assert.Equal("/route1", pathData.VirtualPath); - var namedRouter = Assert.IsAssignableFrom<INamedRouter>(pathData.Router); - Assert.Equal("Route1", namedRouter.Name); - Assert.Empty(pathData.DataTokens); - } + // Assert + Assert.Equal("/route1", pathData.VirtualPath); + var namedRouter = Assert.IsAssignableFrom<INamedRouter>(pathData.Router); + Assert.Equal("Route1", namedRouter.Name); + Assert.Empty(pathData.DataTokens); + } - [Fact] - public void NamedRouteTests_GetNamedRoute_AmbiguousRoutesInCollection_ThrowsForAmbiguousRoute() - { - // Arrange - var ambiguousRoute = "ambiguousRoute"; - var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", ambiguousRoute, "Route4" }); - - // Add Duplicate route. - routeCollection.Add(CreateNamedRoute(ambiguousRoute)); - var virtualPathContext = CreateVirtualPathContext(routeName: ambiguousRoute, options: GetRouteOptions()); - - // Act & Assert - var ex = Assert.Throws<InvalidOperationException>(() => routeCollection.GetVirtualPath(virtualPathContext)); - Assert.Equal( - "The supplied route name 'ambiguousRoute' is ambiguous and matched more than one route.", - ex.Message); - } + [Fact] + public void NamedRouteTests_GetNamedRoute_AmbiguousRoutesInCollection_ThrowsForAmbiguousRoute() + { + // Arrange + var ambiguousRoute = "ambiguousRoute"; + var routeCollection = GetNestedRouteCollection(new string[] { "Route1", "Route2", ambiguousRoute, "Route4" }); + + // Add Duplicate route. + routeCollection.Add(CreateNamedRoute(ambiguousRoute)); + var virtualPathContext = CreateVirtualPathContext(routeName: ambiguousRoute, options: GetRouteOptions()); + + // Act & Assert + var ex = Assert.Throws<InvalidOperationException>(() => routeCollection.GetVirtualPath(virtualPathContext)); + Assert.Equal( + "The supplied route name 'ambiguousRoute' is ambiguous and matched more than one route.", + ex.Message); + } - [Fact] - public void GetVirtualPath_AmbiguousRoutes_RequiresRouteValueValidation_Error() - { - // Arrange - var namedRoute = CreateNamedRoute("Ambiguous", accept: false); + [Fact] + public void GetVirtualPath_AmbiguousRoutes_RequiresRouteValueValidation_Error() + { + // Arrange + var namedRoute = CreateNamedRoute("Ambiguous", accept: false); - var routeCollection = new RouteCollection(); - routeCollection.Add(namedRoute); + var routeCollection = new RouteCollection(); + routeCollection.Add(namedRoute); - var innerRouteCollection = new RouteCollection(); - innerRouteCollection.Add(namedRoute); - routeCollection.Add(innerRouteCollection); + var innerRouteCollection = new RouteCollection(); + innerRouteCollection.Add(namedRoute); + routeCollection.Add(innerRouteCollection); - var virtualPathContext = CreateVirtualPathContext("Ambiguous"); + var virtualPathContext = CreateVirtualPathContext("Ambiguous"); - // Act & Assert - var ex = Assert.Throws<InvalidOperationException>(() => routeCollection.GetVirtualPath(virtualPathContext)); - Assert.Equal("The supplied route name 'Ambiguous' is ambiguous and matched more than one route.", ex.Message); - } + // Act & Assert + var ex = Assert.Throws<InvalidOperationException>(() => routeCollection.GetVirtualPath(virtualPathContext)); + Assert.Equal("The supplied route name 'Ambiguous' is ambiguous and matched more than one route.", ex.Message); + } - // "Integration" tests for RouteCollection + // "Integration" tests for RouteCollection - public static IEnumerable<object[]> IntegrationTestData + public static IEnumerable<object[]> IntegrationTestData + { + get { - get - { - yield return new object[] { + yield return new object[] { "{controller}/{action}", new RouteValueDictionary { { "controller", "Home" }, { "action", "Index" } }, "/home/index", true }; - yield return new object[] { + yield return new object[] { "{controller}/{action}/", new RouteValueDictionary { { "controller", "Home" }, { "action", "Index" } }, "/Home/Index", false }; - yield return new object[] { + yield return new object[] { "api/{action}/", new RouteValueDictionary { { "action", "Create" } }, "/api/create", true }; - yield return new object[] { + yield return new object[] { "api/{action}/{id}", new RouteValueDictionary { { "action", "Create" }, @@ -367,7 +367,7 @@ namespace Microsoft.AspNetCore.Routing "/api/create/23?Param1=Value1&Param2=Value2", true }; - yield return new object[] { + yield return new object[] { "api/{action}/{id}", new RouteValueDictionary { { "action", "Create" }, @@ -376,39 +376,39 @@ namespace Microsoft.AspNetCore.Routing { "Param2", "Value2" } }, "/api/Create/23?Param1=Value1&Param2=Value2", false }; - } } + } - [Theory] - [MemberData(nameof(IntegrationTestData))] - public void GetVirtualPath_Success( - string template, - RouteValueDictionary values, - string expectedUrl, - bool lowercaseUrls) - { - // Arrange - var routeCollection = new RouteCollection(); - var route = CreateTemplateRoute(template); - routeCollection.Add(route); - var context = CreateVirtualPathContext(values, options: GetRouteOptions(lowercaseUrls)); - - // Act - var pathData = routeCollection.GetVirtualPath(context); - - // Assert - Assert.Equal(expectedUrl, pathData.VirtualPath); - Assert.Same(route, pathData.Router); - Assert.Empty(pathData.DataTokens); - } + [Theory] + [MemberData(nameof(IntegrationTestData))] + public void GetVirtualPath_Success( + string template, + RouteValueDictionary values, + string expectedUrl, + bool lowercaseUrls) + { + // Arrange + var routeCollection = new RouteCollection(); + var route = CreateTemplateRoute(template); + routeCollection.Add(route); + var context = CreateVirtualPathContext(values, options: GetRouteOptions(lowercaseUrls)); + + // Act + var pathData = routeCollection.GetVirtualPath(context); + + // Assert + Assert.Equal(expectedUrl, pathData.VirtualPath); + Assert.Same(route, pathData.Router); + Assert.Empty(pathData.DataTokens); + } - public static IEnumerable<object[]> RestoresRouteDataForEachRouterData + public static IEnumerable<object[]> RestoresRouteDataForEachRouterData + { + get { - get - { - // Here 'area' segment doesn't have a value but the later segments have values. This is an invalid - // route match and the url generation should look into the next available route in the collection. - yield return new object[] { + // Here 'area' segment doesn't have a value but the later segments have values. This is an invalid + // route match and the url generation should look into the next available route in the collection. + yield return new object[] { new Route[] { CreateTemplateRoute("{area?}/{controller=Home}/{action=Index}/{id?}", "1"), @@ -418,9 +418,9 @@ namespace Microsoft.AspNetCore.Routing "/Test", "2" }; - // Here the segment 'a' is valid but 'b' is not as it would be empty. This would be an invalid route match, but - // the route value of 'a' should still be present to be evaluated for the next available route. - yield return new object[] { + // Here the segment 'a' is valid but 'b' is not as it would be empty. This would be an invalid route match, but + // the route value of 'a' should still be present to be evaluated for the next available route. + yield return new object[] { new[] { CreateTemplateRoute("{a}/{b?}/{c}", "1"), @@ -429,284 +429,283 @@ namespace Microsoft.AspNetCore.Routing new RouteValueDictionary(new { a = "Test", c = "Foo" }), "/Test?c=Foo", "2" }; - } } + } - [Theory] - [MemberData(nameof(RestoresRouteDataForEachRouterData))] - public void GetVirtualPath_RestoresRouteData_ForEachRouter( - Route[] routes, - RouteValueDictionary routeValues, - string expectedUrl, - string expectedRouteToMatch) + [Theory] + [MemberData(nameof(RestoresRouteDataForEachRouterData))] + public void GetVirtualPath_RestoresRouteData_ForEachRouter( + Route[] routes, + RouteValueDictionary routeValues, + string expectedUrl, + string expectedRouteToMatch) + { + // Arrange + var routeCollection = new RouteCollection(); + foreach (var route in routes) { - // Arrange - var routeCollection = new RouteCollection(); - foreach (var route in routes) - { - routeCollection.Add(route); - } - var context = CreateVirtualPathContext(routeValues); - - // Act - var pathData = routeCollection.GetVirtualPath(context); - - // Assert - Assert.Equal(expectedUrl, pathData.VirtualPath); - Assert.Same(expectedRouteToMatch, ((INamedRouter)pathData.Router).Name); - Assert.Empty(pathData.DataTokens); + routeCollection.Add(route); } + var context = CreateVirtualPathContext(routeValues); - [Fact] - public void GetVirtualPath_NoBestEffort_NoMatch() - { - // Arrange - var route1 = CreateRoute(accept: false, match: false, matchValue: "bad"); - var route2 = CreateRoute(accept: false, match: false, matchValue: "bad"); - var route3 = CreateRoute(accept: false, match: false, matchValue: "bad"); + // Act + var pathData = routeCollection.GetVirtualPath(context); - var routeCollection = new RouteCollection(); - routeCollection.Add(route1.Object); - routeCollection.Add(route2.Object); - routeCollection.Add(route3.Object); + // Assert + Assert.Equal(expectedUrl, pathData.VirtualPath); + Assert.Same(expectedRouteToMatch, ((INamedRouter)pathData.Router).Name); + Assert.Empty(pathData.DataTokens); + } - var virtualPathContext = CreateVirtualPathContext(); + [Fact] + public void GetVirtualPath_NoBestEffort_NoMatch() + { + // Arrange + var route1 = CreateRoute(accept: false, match: false, matchValue: "bad"); + var route2 = CreateRoute(accept: false, match: false, matchValue: "bad"); + var route3 = CreateRoute(accept: false, match: false, matchValue: "bad"); - // Act - var path = routeCollection.GetVirtualPath(virtualPathContext); + var routeCollection = new RouteCollection(); + routeCollection.Add(route1.Object); + routeCollection.Add(route2.Object); + routeCollection.Add(route3.Object); - Assert.Null(path); + var virtualPathContext = CreateVirtualPathContext(); - // All of these should be called - route1.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once()); - route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once()); - route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once()); - } + // Act + var path = routeCollection.GetVirtualPath(virtualPathContext); + + Assert.Null(path); - // DataTokens test data for RouterCollection.GetVirtualPath - public static IEnumerable<object[]> DataTokensTestData + // All of these should be called + route1.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once()); + route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once()); + route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once()); + } + + // DataTokens test data for RouterCollection.GetVirtualPath + public static IEnumerable<object[]> DataTokensTestData + { + get { - get - { - yield return new object[] { null, null }; - yield return new object[] { new RouteValueDictionary(), null }; - yield return new object[] { new RouteValueDictionary() { { "tokenKey", "tokenValue" } }, null }; - - yield return new object[] { null, "routerA" }; - yield return new object[] { new RouteValueDictionary(), "routerA" }; - yield return new object[] { new RouteValueDictionary() { { "tokenKey", "tokenValue" } }, "routerA" }; - } + yield return new object[] { null, null }; + yield return new object[] { new RouteValueDictionary(), null }; + yield return new object[] { new RouteValueDictionary() { { "tokenKey", "tokenValue" } }, null }; + + yield return new object[] { null, "routerA" }; + yield return new object[] { new RouteValueDictionary(), "routerA" }; + yield return new object[] { new RouteValueDictionary() { { "tokenKey", "tokenValue" } }, "routerA" }; } + } - private static RouteCollection GetRouteCollectionWithNamedRoutes(IEnumerable<string> routeNames) + private static RouteCollection GetRouteCollectionWithNamedRoutes(IEnumerable<string> routeNames) + { + var routes = new RouteCollection(); + foreach (var routeName in routeNames) { - var routes = new RouteCollection(); - foreach (var routeName in routeNames) - { - var route1 = CreateNamedRoute(routeName, accept: true); - routes.Add(route1); - } - - return routes; + var route1 = CreateNamedRoute(routeName, accept: true); + routes.Add(route1); } - private static RouteCollection GetNestedRouteCollection(string[] routeNames) + return routes; + } + + private static RouteCollection GetNestedRouteCollection(string[] routeNames) + { + int index = Random.Shared.Next(0, routeNames.Length - 1); + var first = routeNames.Take(index).ToArray(); + var second = routeNames.Skip(index).ToArray(); + + var rc1 = GetRouteCollectionWithNamedRoutes(first); + var rc2 = GetRouteCollectionWithNamedRoutes(second); + var rc3 = new RouteCollection(); + var rc4 = new RouteCollection(); + + rc1.Add(rc3); + rc4.Add(rc2); + + // Add a few unnamedRoutes. + rc1.Add(CreateRoute(accept: false).Object); + rc2.Add(CreateRoute(accept: false).Object); + rc3.Add(CreateRoute(accept: false).Object); + rc3.Add(CreateRoute(accept: false).Object); + rc4.Add(CreateRoute(accept: false).Object); + rc4.Add(CreateRoute(accept: false).Object); + + var routeCollection = new RouteCollection(); + routeCollection.Add(rc1); + routeCollection.Add(rc4); + + return routeCollection; + } + + private static INamedRouter CreateNamedRoute(string name, bool accept = false, string matchValue = null) + { + if (matchValue == null) { - int index = Random.Shared.Next(0, routeNames.Length - 1); - var first = routeNames.Take(index).ToArray(); - var second = routeNames.Skip(index).ToArray(); - - var rc1 = GetRouteCollectionWithNamedRoutes(first); - var rc2 = GetRouteCollectionWithNamedRoutes(second); - var rc3 = new RouteCollection(); - var rc4 = new RouteCollection(); - - rc1.Add(rc3); - rc4.Add(rc2); - - // Add a few unnamedRoutes. - rc1.Add(CreateRoute(accept: false).Object); - rc2.Add(CreateRoute(accept: false).Object); - rc3.Add(CreateRoute(accept: false).Object); - rc3.Add(CreateRoute(accept: false).Object); - rc4.Add(CreateRoute(accept: false).Object); - rc4.Add(CreateRoute(accept: false).Object); - - var routeCollection = new RouteCollection(); - routeCollection.Add(rc1); - routeCollection.Add(rc4); - - return routeCollection; + matchValue = name; } - private static INamedRouter CreateNamedRoute(string name, bool accept = false, string matchValue = null) + var target = new Mock<INamedRouter>(MockBehavior.Strict); + target + .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) + .Returns<VirtualPathContext>(c => + c.RouteName == name ? new VirtualPathData(target.Object, matchValue) : null) + .Verifiable(); + + target + .SetupGet(e => e.Name) + .Returns(name); + + target + .Setup(e => e.RouteAsync(It.IsAny<RouteContext>())) + .Callback<RouteContext>((c) => c.Handler = accept ? NullHandler : null) + .Returns(Task.FromResult<object>(null)) + .Verifiable(); + + return target.Object; + } + + private static Route CreateTemplateRoute( + string template, + string routerName = null, + RouteValueDictionary dataTokens = null, + IInlineConstraintResolver constraintResolver = null) + { + var target = new Mock<IRouter>(MockBehavior.Strict); + target + .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) + .Returns<VirtualPathContext>(rc => null); + + if (constraintResolver == null) { - if (matchValue == null) - { - matchValue = name; - } - - var target = new Mock<INamedRouter>(MockBehavior.Strict); - target - .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) - .Returns<VirtualPathContext>(c => - c.RouteName == name ? new VirtualPathData(target.Object, matchValue) : null) - .Verifiable(); - - target - .SetupGet(e => e.Name) - .Returns(name); - - target - .Setup(e => e.RouteAsync(It.IsAny<RouteContext>())) - .Callback<RouteContext>((c) => c.Handler = accept ? NullHandler : null) - .Returns(Task.FromResult<object>(null)) - .Verifiable(); - - return target.Object; + constraintResolver = new Mock<IInlineConstraintResolver>().Object; } - private static Route CreateTemplateRoute( - string template, - string routerName = null, - RouteValueDictionary dataTokens = null, - IInlineConstraintResolver constraintResolver = null) + return new Route( + target.Object, + routerName, + template, + defaults: null, + constraints: null, + dataTokens: dataTokens, + inlineConstraintResolver: constraintResolver); + } + + private static VirtualPathContext CreateVirtualPathContext( + string routeName = null, + ILoggerFactory loggerFactory = null, + Action<RouteOptions> options = null) + { + if (loggerFactory == null) { - var target = new Mock<IRouter>(MockBehavior.Strict); - target - .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) - .Returns<VirtualPathContext>(rc => null); - - if (constraintResolver == null) - { - constraintResolver = new Mock<IInlineConstraintResolver>().Object; - } - - return new Route( - target.Object, - routerName, - template, - defaults: null, - constraints: null, - dataTokens: dataTokens, - inlineConstraintResolver: constraintResolver); + loggerFactory = NullLoggerFactory.Instance; } - private static VirtualPathContext CreateVirtualPathContext( - string routeName = null, - ILoggerFactory loggerFactory = null, - Action<RouteOptions> options = null) + var request = new Mock<HttpRequest>(MockBehavior.Strict); + + var services = new ServiceCollection(); + services.AddOptions(); + services.AddRouting(); + if (options != null) { - if (loggerFactory == null) - { - loggerFactory = NullLoggerFactory.Instance; - } - - var request = new Mock<HttpRequest>(MockBehavior.Strict); - - var services = new ServiceCollection(); - services.AddOptions(); - services.AddRouting(); - if (options != null) - { - services.Configure(options); - } - - var context = new Mock<HttpContext>(MockBehavior.Strict); - context.SetupGet(m => m.RequestServices).Returns(services.BuildServiceProvider()); - context.SetupGet(c => c.Request).Returns(request.Object); - - return new VirtualPathContext(context.Object, null, null, routeName); + services.Configure(options); } - private static VirtualPathContext CreateVirtualPathContext( - RouteValueDictionary values, - Action<RouteOptions> options = null, - string routeName = null) + var context = new Mock<HttpContext>(MockBehavior.Strict); + context.SetupGet(m => m.RequestServices).Returns(services.BuildServiceProvider()); + context.SetupGet(c => c.Request).Returns(request.Object); + + return new VirtualPathContext(context.Object, null, null, routeName); + } + + private static VirtualPathContext CreateVirtualPathContext( + RouteValueDictionary values, + Action<RouteOptions> options = null, + string routeName = null) + { + var services = new ServiceCollection(); + services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance); + services.AddOptions(); + services.AddRouting(); + if (options != null) { - var services = new ServiceCollection(); - services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance); - services.AddOptions(); - services.AddRouting(); - if (options != null) - { - services.Configure<RouteOptions>(options); - } - - var context = new DefaultHttpContext - { - RequestServices = services.BuildServiceProvider(), - }; - - return new VirtualPathContext( - context, - ambientValues: null, - values: values, - routeName: routeName); + services.Configure<RouteOptions>(options); } - private static RouteContext CreateRouteContext( - string requestPath, - ILoggerFactory loggerFactory = null, - RouteOptions options = null) + var context = new DefaultHttpContext { - if (loggerFactory == null) - { - loggerFactory = NullLoggerFactory.Instance; - } - - if (options == null) - { - options = new RouteOptions(); - } - - var request = new Mock<HttpRequest>(MockBehavior.Strict); - request.SetupGet(r => r.Path).Returns(requestPath); - - var optionsAccessor = new Mock<IOptions<RouteOptions>>(MockBehavior.Strict); - optionsAccessor.SetupGet(o => o.Value).Returns(options); - - var context = new Mock<HttpContext>(MockBehavior.Strict); - context.Setup(m => m.RequestServices.GetService(typeof(ILoggerFactory))) - .Returns(loggerFactory); - context.Setup(m => m.RequestServices.GetService(typeof(IOptions<RouteOptions>))) - .Returns(optionsAccessor.Object); - context.SetupGet(c => c.Request).Returns(request.Object); - - return new RouteContext(context.Object); - } + RequestServices = services.BuildServiceProvider(), + }; + + return new VirtualPathContext( + context, + ambientValues: null, + values: values, + routeName: routeName); + } - private static Mock<IRouter> CreateRoute( - bool accept = true, - bool match = false, - string matchValue = "value") + private static RouteContext CreateRouteContext( + string requestPath, + ILoggerFactory loggerFactory = null, + RouteOptions options = null) + { + if (loggerFactory == null) { - var target = new Mock<IRouter>(MockBehavior.Strict); - target - .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) - .Returns(accept || match ? new VirtualPathData(target.Object, matchValue) : null) - .Verifiable(); - - target - .Setup(e => e.RouteAsync(It.IsAny<RouteContext>())) - .Callback<RouteContext>((c) => c.Handler = accept ? NullHandler : null) - .Returns(Task.FromResult<object>(null)) - .Verifiable(); - - return target; + loggerFactory = NullLoggerFactory.Instance; } - private static Action<RouteOptions> GetRouteOptions( - bool lowerCaseUrls = false, - bool appendTrailingSlash = false, - bool lowercaseQueryStrings = false) + if (options == null) { - return (options) => - { - options.LowercaseUrls = lowerCaseUrls; - options.AppendTrailingSlash = appendTrailingSlash; - options.LowercaseQueryStrings = lowercaseQueryStrings; - }; + options = new RouteOptions(); } + + var request = new Mock<HttpRequest>(MockBehavior.Strict); + request.SetupGet(r => r.Path).Returns(requestPath); + + var optionsAccessor = new Mock<IOptions<RouteOptions>>(MockBehavior.Strict); + optionsAccessor.SetupGet(o => o.Value).Returns(options); + + var context = new Mock<HttpContext>(MockBehavior.Strict); + context.Setup(m => m.RequestServices.GetService(typeof(ILoggerFactory))) + .Returns(loggerFactory); + context.Setup(m => m.RequestServices.GetService(typeof(IOptions<RouteOptions>))) + .Returns(optionsAccessor.Object); + context.SetupGet(c => c.Request).Returns(request.Object); + + return new RouteContext(context.Object); + } + + private static Mock<IRouter> CreateRoute( + bool accept = true, + bool match = false, + string matchValue = "value") + { + var target = new Mock<IRouter>(MockBehavior.Strict); + target + .Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>())) + .Returns(accept || match ? new VirtualPathData(target.Object, matchValue) : null) + .Verifiable(); + + target + .Setup(e => e.RouteAsync(It.IsAny<RouteContext>())) + .Callback<RouteContext>((c) => c.Handler = accept ? NullHandler : null) + .Returns(Task.FromResult<object>(null)) + .Verifiable(); + + return target; + } + + private static Action<RouteOptions> GetRouteOptions( + bool lowerCaseUrls = false, + bool appendTrailingSlash = false, + bool lowercaseQueryStrings = false) + { + return (options) => + { + options.LowercaseUrls = lowerCaseUrls; + options.AppendTrailingSlash = appendTrailingSlash; + options.LowercaseQueryStrings = lowercaseQueryStrings; + }; } } |