зеркало из https://github.com/aspnet/Routing.git
Add sample matcher tests
This commit is contained in:
Родитель
1b470f3d3b
Коммит
08f12f2bfd
|
@ -41,7 +41,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
|
||||
if (context.Handler != null)
|
||||
{
|
||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
||||
await context.Handler(httpContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,18 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matchers
|
||||
{
|
||||
public sealed class MatcherEndpoint : Endpoint
|
||||
{
|
||||
internal static readonly Func<RequestDelegate, RequestDelegate> EmptyInvoker = (next) =>
|
||||
{
|
||||
return (context) => Task.CompletedTask;
|
||||
};
|
||||
|
||||
public MatcherEndpoint(
|
||||
Func<RequestDelegate, RequestDelegate> invoker,
|
||||
string template,
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
// 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.Linq;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matchers
|
||||
{
|
||||
internal static class DispatcherAssert
|
||||
{
|
||||
public static void AssertMatch(IEndpointFeature feature, Endpoint expected)
|
||||
{
|
||||
AssertMatch(feature, expected, new RouteValueDictionary());
|
||||
}
|
||||
|
||||
public static void AssertMatch(IEndpointFeature feature, Endpoint expected, RouteValueDictionary values)
|
||||
{
|
||||
if (feature.Endpoint == null)
|
||||
{
|
||||
throw new XunitException($"Was expected to match '{expected.DisplayName}' but did not match.");
|
||||
}
|
||||
|
||||
if (!object.ReferenceEquals(expected, feature.Endpoint))
|
||||
{
|
||||
throw new XunitException(
|
||||
$"Was expected to match '{expected.DisplayName}' but matched " +
|
||||
$"'{feature.Endpoint.DisplayName}' with values: {FormatRouteValues(feature.Values)}.");
|
||||
}
|
||||
|
||||
if (values.Count != feature.Values.Count ||
|
||||
!values.OrderBy(kvp => kvp.Key).SequenceEqual(feature.Values.OrderBy(kvp => kvp.Key)))
|
||||
{
|
||||
throw new XunitException(
|
||||
$"Was expected to match '{expected.DisplayName}' with values {FormatRouteValues(values)} but matched " +
|
||||
$"values: {FormatRouteValues(feature.Values)}.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertNotMatch(IEndpointFeature feature)
|
||||
{
|
||||
if (feature.Endpoint != null)
|
||||
{
|
||||
throw new XunitException(
|
||||
$"Was expected not to match '{feature.Endpoint.DisplayName}' " +
|
||||
$"but matched with values: {FormatRouteValues(feature.Values)}.");
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatRouteValues(RouteValueDictionary values)
|
||||
{
|
||||
return "{" + string.Join(", ", values.Select(kvp => $"{kvp.Key} = '{kvp.Value}'")) + "}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matchers
|
||||
{
|
||||
public abstract class MatcherConformanceTest
|
||||
{
|
||||
internal abstract Matcher CreateMatcher(MatcherEndpoint endpoint);
|
||||
|
||||
[Fact]
|
||||
public virtual async Task Match_SingleLiteralSegment_Success()
|
||||
{
|
||||
// Arrange
|
||||
var (matcher, endpoint) = CreateMatcher("/simple");
|
||||
var (httpContext, feature) = CreateContext("/simple");
|
||||
|
||||
// Act
|
||||
await matcher.MatchAsync(httpContext, feature);
|
||||
|
||||
// Assert
|
||||
DispatcherAssert.AssertMatch(feature, endpoint);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("simple")]
|
||||
[InlineData("/simple")]
|
||||
[InlineData("~/simple")]
|
||||
public virtual async Task Match_Sanitizies_TemplatePrefix(string template)
|
||||
{
|
||||
// Arrange
|
||||
var (matcher, endpoint) = CreateMatcher(template);
|
||||
var (httpContext, feature) = CreateContext("/simple");
|
||||
|
||||
// Act
|
||||
await matcher.MatchAsync(httpContext, feature);
|
||||
|
||||
// Assert
|
||||
DispatcherAssert.AssertMatch(feature, endpoint);
|
||||
}
|
||||
|
||||
internal static (HttpContext httpContext, IEndpointFeature feature) CreateContext(string path)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Request.Method = "TEST";
|
||||
httpContext.Request.Path = path;
|
||||
httpContext.RequestServices = CreateServices();
|
||||
|
||||
var feature = new EndpointFeature();
|
||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
||||
|
||||
return (httpContext, feature);
|
||||
}
|
||||
|
||||
// The older routing implementations retrieve services when they first execute.
|
||||
internal static IServiceProvider CreateServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
internal static MatcherEndpoint CreateEndpoint(string template)
|
||||
{
|
||||
return new MatcherEndpoint(
|
||||
MatcherEndpoint.EmptyInvoker,
|
||||
template,
|
||||
null,
|
||||
0,
|
||||
EndpointMetadataCollection.Empty, "endpoint: " + template);
|
||||
}
|
||||
|
||||
internal (Matcher matcher, MatcherEndpoint endpoint) CreateMatcher(string template)
|
||||
{
|
||||
var endpoint = CreateEndpoint(template);
|
||||
return (CreateMatcher(endpoint), endpoint);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing.Tree;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matchers
|
||||
{
|
||||
// This is an adapter to use TreeRouter in the conformance tests
|
||||
internal class TreeRouterMatcher : Matcher
|
||||
{
|
||||
private readonly TreeRouter _inner;
|
||||
|
||||
internal TreeRouterMatcher(TreeRouter inner)
|
||||
{
|
||||
_inner = inner;
|
||||
}
|
||||
|
||||
public async override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
if (feature == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(feature));
|
||||
}
|
||||
|
||||
var context = new RouteContext(httpContext);
|
||||
await _inner.RouteAsync(context);
|
||||
|
||||
if (context.Handler != null)
|
||||
{
|
||||
httpContext.Features.Get<IEndpointFeature>().Values = context.RouteData.Values;
|
||||
await context.Handler(httpContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Routing.Internal;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
using Microsoft.AspNetCore.Routing.Tree;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matchers
|
||||
{
|
||||
public class TreeRouterMatcherConformanceTest : MatcherConformanceTest
|
||||
{
|
||||
internal override Matcher CreateMatcher(MatcherEndpoint endpoint)
|
||||
{
|
||||
var builder = new TreeRouteBuilder(
|
||||
NullLoggerFactory.Instance,
|
||||
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
|
||||
new DefaultInlineConstraintResolver(Options.Create(new RouteOptions())));
|
||||
|
||||
var handler = new RouteHandler(c =>
|
||||
{
|
||||
var feature = c.Features.Get<IEndpointFeature>();
|
||||
feature.Endpoint = endpoint;
|
||||
feature.Invoker = MatcherEndpoint.EmptyInvoker;
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
builder.MapInbound(handler, TemplateParser.Parse(endpoint.Template), "default", 0);
|
||||
|
||||
return new TreeRouterMatcher(builder.Build());
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче