aspnetcore/test/Microsoft.AspNetCore.Blazor.../Routing/RouteTableTests.cs

219 lines
6.8 KiB
C#

// 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 System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Blazor.Routing;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Test.Routing
{
public class RouteTableTests
{
[Fact]
public void CanMatchRootTemplate()
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/").Build();
var context = new RouteContext("/");
// Act
routeTable.Route(context);
// Assert
Assert.NotNull(context.Handler);
}
[Fact]
public void CanMatchLiteralTemplate()
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/literal").Build();
var context = new RouteContext("/literal/");
// Act
routeTable.Route(context);
// Assert
Assert.NotNull(context.Handler);
}
[Fact]
public void CanMatchTemplateWithMultipleLiterals()
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/some/awesome/route/").Build();
var context = new RouteContext("/some/awesome/route");
// Act
routeTable.Route(context);
// Assert
Assert.NotNull(context.Handler);
}
[Fact]
public void RouteMatchingIsCaseInsensitive()
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/some/AWESOME/route/").Build();
var context = new RouteContext("/Some/awesome/RouTe");
// Act
routeTable.Route(context);
// Assert
Assert.NotNull(context.Handler);
}
[Fact]
public void DoesNotMatchIfSegmentsDontMatch()
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/some/AWESOME/route/").Build();
var context = new RouteContext("/some/brilliant/route");
// Act
routeTable.Route(context);
// Assert
Assert.Null(context.Handler);
}
[Theory]
[InlineData("/some")]
[InlineData("/some/awesome/route/with/extra/segments")]
public void DoesNotMatchIfDifferentNumberOfSegments(string path)
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/some/awesome/route/").Build();
var context = new RouteContext(path);
// Act
routeTable.Route(context);
// Assert
Assert.Null(context.Handler);
}
[Theory]
[InlineData("/value1", "value1")]
[InlineData("/value2/", "value2")]
public void CanMatchParameterTemplate(string path, string expectedValue)
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/{parameter}").Build();
var context = new RouteContext(path);
// Act
routeTable.Route(context);
// Assert
Assert.NotNull(context.Handler);
Assert.Single(context.Parameters, p => p.Key == "parameter" && p.Value == expectedValue);
}
[Fact]
public void CanMatchTemplateWithMultipleParameters()
{
// Arrange
var routeTable = new TestRouteTableBuilder().AddRoute("/{some}/awesome/{route}/").Build();
var context = new RouteContext("/an/awesome/path");
var expectedParameters = new Dictionary<string, string>
{
["some"] = "an",
["route"] = "path"
};
// Act
routeTable.Route(context);
// Assert
Assert.NotNull(context.Handler);
Assert.Equal(expectedParameters, context.Parameters);
}
[Fact]
public void PrefersLiteralTemplateOverTemplateWithParameters()
{
// Arrange
var routeTable = new TestRouteTableBuilder()
.AddRoute("/an/awesome/path")
.AddRoute("/{some}/awesome/{route}/").Build();
var context = new RouteContext("/an/awesome/path");
// Act
routeTable.Route(context);
// Assert
Assert.NotNull(context.Handler);
Assert.Null(context.Parameters);
}
[Fact]
public void PrefersShorterRoutesOverLongerRoutes()
{
// Arrange & Act
var handler = typeof(int);
var routeTable = new TestRouteTableBuilder()
.AddRoute("/an/awesome/path")
.AddRoute("/an/awesome/", handler).Build();
// Act
Assert.Equal("an/awesome", routeTable.Routes[0].Template.TemplateText);
}
[Fact]
public void ProducesAStableOrderForNonAmbiguousRoutes()
{
// Arrange & Act
var handler = typeof(int);
var routeTable = new TestRouteTableBuilder()
.AddRoute("/an/awesome/", handler)
.AddRoute("/a/brilliant/").Build();
// Act
Assert.Equal("a/brilliant", routeTable.Routes[0].Template.TemplateText);
}
[Theory]
[InlineData("/literal", "/Literal/")]
[InlineData("/{parameter}", "/{parameter}/")]
[InlineData("/literal/{parameter}", "/Literal/{something}")]
[InlineData("/{parameter}/literal/{something}", "{param}/Literal/{else}")]
public void DetectsAmbigousRoutes(string left, string right)
{
// Arrange
var expectedMessage = $@"The following routes are ambiguous:
'{left.Trim('/')}' in '{typeof(object).FullName}'
'{right.Trim('/')}' in '{typeof(object).FullName}'
";
// Act
var exception = Assert.Throws<InvalidOperationException>(() => new TestRouteTableBuilder()
.AddRoute(left)
.AddRoute(right).Build());
Assert.Equal(expectedMessage, exception.Message);
}
private class TestRouteTableBuilder
{
IList<(string, Type)> _routeTemplates = new List<(string, Type)>();
Type _handler = typeof(object);
public TestRouteTableBuilder AddRoute(string template, Type handler = null)
{
_routeTemplates.Add((template, handler ?? _handler));
return this;
}
public RouteTable Build() => new RouteTable(_routeTemplates
.Select(rt => new RouteEntry(TemplateParser.ParseTemplate(rt.Item1), rt.Item2))
.OrderBy(id => id, RouteTable.RoutePrecedence)
.ToArray());
}
}
}