Create collections on DfaNode as needed (#779)
This commit is contained in:
parent
a777a4cdd5
commit
0f5d471dfd
|
|
@ -64,9 +64,12 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
// We can safely index into visited because this is a post-order traversal,
|
||||
// all of the children of this node are already in the dictionary.
|
||||
|
||||
foreach (var literal in node.Literals)
|
||||
if (node.Literals != null)
|
||||
{
|
||||
writer.WriteLine($"{label} -> {visited[literal.Value]} [label=\"/{literal.Key}\"]");
|
||||
foreach (var literal in node.Literals)
|
||||
{
|
||||
writer.WriteLine($"{label} -> {visited[literal.Value]} [label=\"/{literal.Key}\"]");
|
||||
}
|
||||
}
|
||||
|
||||
if (node.Parameters != null)
|
||||
|
|
@ -79,9 +82,12 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
writer.WriteLine($"{label} -> {visited[node.CatchAll]} [label=\"/**\"]");
|
||||
}
|
||||
|
||||
foreach (var policy in node.PolicyEdges)
|
||||
if (node.PolicyEdges != null)
|
||||
{
|
||||
writer.WriteLine($"{label} -> {visited[policy.Value]} [label=\"{policy.Key}\"]");
|
||||
foreach (var policy in node.PolicyEdges)
|
||||
{
|
||||
writer.WriteLine($"{label} -> {visited[policy.Value]} [label=\"{policy.Key}\"]");
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteLine($"{label} [label=\"{node.Label}\"]");
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
for (var j = 0; j < parents.Count; j++)
|
||||
{
|
||||
var parent = parents[j];
|
||||
parent.Matches.Add(endpoint);
|
||||
parent.AddMatch(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -139,15 +139,17 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var part = segment.Parts[0];
|
||||
if (segment.IsSimple && part is RoutePatternLiteralPart literalPart)
|
||||
{
|
||||
DfaNode next = null;
|
||||
var literal = literalPart.Content;
|
||||
if (!parent.Literals.TryGetValue(literal, out var next))
|
||||
if (parent.Literals == null ||
|
||||
!parent.Literals.TryGetValue(literal, out next))
|
||||
{
|
||||
next = new DfaNode()
|
||||
{
|
||||
PathDepth = parent.PathDepth + 1,
|
||||
Label = parent.Label + literal + "/",
|
||||
};
|
||||
parent.Literals.Add(literal, next);
|
||||
parent.AddLiteral(literal, next);
|
||||
}
|
||||
|
||||
nextParents.Add(next);
|
||||
|
|
@ -157,7 +159,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
// A catch all should traverse all literal nodes as well as parameter nodes
|
||||
// we don't need to create the parameter node here because of ordering
|
||||
// all catchalls will be processed after all parameters.
|
||||
nextParents.AddRange(parent.Literals.Values);
|
||||
if (parent.Literals != null)
|
||||
{
|
||||
nextParents.AddRange(parent.Literals.Values);
|
||||
}
|
||||
if (parent.Parameters != null)
|
||||
{
|
||||
nextParents.Add(parent.Parameters);
|
||||
|
|
@ -181,7 +186,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
parent.CatchAll.CatchAll = parent.CatchAll;
|
||||
}
|
||||
|
||||
parent.CatchAll.Matches.Add(endpoint);
|
||||
parent.CatchAll.AddMatch(endpoint);
|
||||
}
|
||||
else if (segment.IsSimple && part.IsParameter)
|
||||
{
|
||||
|
|
@ -195,7 +200,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
}
|
||||
|
||||
// A parameter should traverse all literal nodes as well as the parameter node
|
||||
nextParents.AddRange(parent.Literals.Values);
|
||||
if (parent.Literals != null)
|
||||
{
|
||||
nextParents.AddRange(parent.Literals.Values);
|
||||
}
|
||||
nextParents.Add(parent.Parameters);
|
||||
}
|
||||
else
|
||||
|
|
@ -213,7 +221,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
};
|
||||
}
|
||||
|
||||
nextParents.AddRange(parent.Literals.Values);
|
||||
if (parent.Literals != null)
|
||||
{
|
||||
nextParents.AddRange(parent.Literals.Values);
|
||||
}
|
||||
nextParents.Add(parent.Parameters);
|
||||
}
|
||||
}
|
||||
|
|
@ -311,7 +322,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
List<DfaState> states,
|
||||
List<(JumpTableBuilder pathBuilder, PolicyJumpTableBuilder policyBuilder)> tableBuilders)
|
||||
{
|
||||
node.Matches.Sort(_comparer);
|
||||
node.Matches?.Sort(_comparer);
|
||||
|
||||
var stateIndex = states.Count;
|
||||
|
||||
|
|
@ -321,15 +332,18 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var pathBuilder = new JumpTableBuilder();
|
||||
tableBuilders.Add((pathBuilder, null));
|
||||
|
||||
foreach (var kvp in node.Literals)
|
||||
if (node.Literals != null)
|
||||
{
|
||||
if (kvp.Key == null)
|
||||
foreach (var kvp in node.Literals)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (kvp.Key == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var transition = Transition(kvp.Value);
|
||||
pathBuilder.AddEntry(kvp.Key, transition);
|
||||
var transition = Transition(kvp.Value);
|
||||
pathBuilder.AddEntry(kvp.Key, transition);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.Parameters != null &&
|
||||
|
|
@ -360,7 +374,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
pathBuilder.ExitDestination = pathBuilder.DefaultDestination;
|
||||
}
|
||||
|
||||
if (node.PolicyEdges.Count > 0)
|
||||
if (node.PolicyEdges != null && node.PolicyEdges.Count > 0)
|
||||
{
|
||||
var policyBuilder = new PolicyJumpTableBuilder(node.NodeBuilder);
|
||||
tableBuilders[stateIndex] = (pathBuilder, policyBuilder);
|
||||
|
|
@ -384,7 +398,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
// endpoint.
|
||||
internal Candidate[] CreateCandidates(IReadOnlyList<Endpoint> endpoints)
|
||||
{
|
||||
if (endpoints.Count == 0)
|
||||
if (endpoints == null || endpoints.Count == 0)
|
||||
{
|
||||
return Array.Empty<Candidate>();
|
||||
}
|
||||
|
|
@ -502,7 +516,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
private int[] GetGroupLengths(DfaNode node)
|
||||
{
|
||||
if (node.Matches.Count == 0)
|
||||
var nodeMatches = node.Matches;
|
||||
if (nodeMatches == null || nodeMatches.Count == 0)
|
||||
{
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
|
|
@ -510,16 +525,16 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var groups = new List<int>();
|
||||
|
||||
var length = 1;
|
||||
var exemplar = node.Matches[0];
|
||||
var exemplar = nodeMatches[0];
|
||||
|
||||
for (var i = 1; i < node.Matches.Count; i++)
|
||||
for (var i = 1; i < nodeMatches.Count; i++)
|
||||
{
|
||||
if (!_comparer.Equals(exemplar, node.Matches[i]))
|
||||
if (!_comparer.Equals(exemplar, nodeMatches[i]))
|
||||
{
|
||||
groups.Add(length);
|
||||
length = 0;
|
||||
|
||||
exemplar = node.Matches[i];
|
||||
exemplar = nodeMatches[i];
|
||||
}
|
||||
|
||||
length++;
|
||||
|
|
@ -561,7 +576,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
private void ApplyPolicies(DfaNode node)
|
||||
{
|
||||
if (node.Matches.Count == 0)
|
||||
if (node.Matches == null || node.Matches.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -578,7 +593,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
for (var j = 0; j < work.Count; j++)
|
||||
{
|
||||
var parent = work[j];
|
||||
if (!nodeBuilder.AppliesToNode(parent.Matches))
|
||||
if (!nodeBuilder.AppliesToNode(parent.Matches ?? (IReadOnlyList<Endpoint>)Array.Empty<Endpoint>()))
|
||||
{
|
||||
// This node-builder doesn't care about this node, so add it to the list
|
||||
// to be processed by the next node-builder.
|
||||
|
|
@ -588,7 +603,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
// This node-builder does apply to this node, so we need to create new nodes for each edge,
|
||||
// and then attach them to the parent.
|
||||
var edges = nodeBuilder.GetEdges(parent.Matches);
|
||||
var edges = nodeBuilder.GetEdges(parent.Matches ?? (IReadOnlyList<Endpoint>)Array.Empty<Endpoint>());
|
||||
for (var k = 0; k < edges.Count; k++)
|
||||
{
|
||||
var edge = edges[k];
|
||||
|
|
@ -598,17 +613,20 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
Label = parent.Label + " " + edge.State.ToString(),
|
||||
};
|
||||
|
||||
next.Matches.AddRange(edge.Endpoints);
|
||||
if (edge.Endpoints.Count > 0)
|
||||
{
|
||||
next.AddMatches(edge.Endpoints);
|
||||
}
|
||||
nextWork.Add(next);
|
||||
|
||||
parent.PolicyEdges.Add(edge.State, next);
|
||||
parent.AddPolicyEdge(edge.State, next);
|
||||
}
|
||||
|
||||
// Associate the node-builder so we can build a jump table later.
|
||||
parent.NodeBuilder = nodeBuilder;
|
||||
|
||||
// The parent no longer has matches, it's not considered a terminal node.
|
||||
parent.Matches.Clear();
|
||||
parent.Matches?.Clear();
|
||||
}
|
||||
|
||||
work = nextWork;
|
||||
|
|
|
|||
|
|
@ -14,13 +14,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
[DebuggerDisplay("{DebuggerToString(),nq}")]
|
||||
internal class DfaNode
|
||||
{
|
||||
public DfaNode()
|
||||
{
|
||||
Literals = new Dictionary<string, DfaNode>(StringComparer.OrdinalIgnoreCase);
|
||||
Matches = new List<Endpoint>();
|
||||
PolicyEdges = new Dictionary<object, DfaNode>();
|
||||
}
|
||||
|
||||
// The depth of the node. The depth indicates the number of segments
|
||||
// that must be processed to arrive at this node.
|
||||
//
|
||||
|
|
@ -30,9 +23,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
// Just for diagnostics and debugging
|
||||
public string Label { get; set; }
|
||||
|
||||
public List<Endpoint> Matches { get; }
|
||||
public List<Endpoint> Matches { get; private set; }
|
||||
|
||||
public Dictionary<string, DfaNode> Literals { get; }
|
||||
public Dictionary<string, DfaNode> Literals { get; private set; }
|
||||
|
||||
public DfaNode Parameters { get; set; }
|
||||
|
||||
|
|
@ -40,13 +33,58 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
public INodeBuilderPolicy NodeBuilder { get; set; }
|
||||
|
||||
public Dictionary<object, DfaNode> PolicyEdges { get; }
|
||||
public Dictionary<object, DfaNode> PolicyEdges { get; private set; }
|
||||
|
||||
public void AddPolicyEdge(object state, DfaNode node)
|
||||
{
|
||||
if (PolicyEdges == null)
|
||||
{
|
||||
PolicyEdges = new Dictionary<object, DfaNode>();
|
||||
}
|
||||
|
||||
PolicyEdges.Add(state, node);
|
||||
}
|
||||
|
||||
public void AddLiteral(string literal, DfaNode node)
|
||||
{
|
||||
if (Literals == null)
|
||||
{
|
||||
Literals = new Dictionary<string, DfaNode>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
Literals.Add(literal, node);
|
||||
}
|
||||
|
||||
public void AddMatch(Endpoint endpoint)
|
||||
{
|
||||
if (Matches == null)
|
||||
{
|
||||
Matches = new List<Endpoint>();
|
||||
}
|
||||
|
||||
Matches.Add(endpoint);
|
||||
}
|
||||
|
||||
public void AddMatches(IEnumerable<Endpoint> endpoints)
|
||||
{
|
||||
if (Matches == null)
|
||||
{
|
||||
Matches = new List<Endpoint>(endpoints);
|
||||
}
|
||||
else
|
||||
{
|
||||
Matches.AddRange(endpoints);
|
||||
}
|
||||
}
|
||||
|
||||
public void Visit(Action<DfaNode> visitor)
|
||||
{
|
||||
foreach (var kvp in Literals)
|
||||
if (Literals != null)
|
||||
{
|
||||
kvp.Value.Visit(visitor);
|
||||
foreach (var kvp in Literals)
|
||||
{
|
||||
kvp.Value.Visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
// Break cycles
|
||||
|
|
@ -61,9 +99,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
CatchAll.Visit(visitor);
|
||||
}
|
||||
|
||||
foreach (var kvp in PolicyEdges)
|
||||
if (PolicyEdges != null)
|
||||
{
|
||||
kvp.Value.Visit(visitor);
|
||||
foreach (var kvp in PolicyEdges)
|
||||
{
|
||||
kvp.Value.Visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
visitor(this);
|
||||
|
|
@ -76,9 +117,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
builder.Append(" d:");
|
||||
builder.Append(PathDepth);
|
||||
builder.Append(" m:");
|
||||
builder.Append(Matches.Count);
|
||||
builder.Append(Matches?.Count ?? 0);
|
||||
builder.Append(" c: ");
|
||||
builder.Append(string.Join(", ", Literals.Select(kvp => $"{kvp.Key}->({FormatNode(kvp.Value)})")));
|
||||
if (Literals != null)
|
||||
{
|
||||
builder.Append(string.Join(", ", Literals.Select(kvp => $"{kvp.Key}->({FormatNode(kvp.Value)})")));
|
||||
}
|
||||
return builder.ToString();
|
||||
|
||||
// DfaNodes can be self-referential, don't traverse cycles.
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
// Assert
|
||||
Assert.Same(endpoint, Assert.Single(root.Matches));
|
||||
Assert.Null(root.Parameters);
|
||||
Assert.Empty(root.Literals);
|
||||
Assert.Null(root.Literals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -46,21 +46,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
Assert.Equal("a", next.Key);
|
||||
|
||||
var a = next.Value;
|
||||
Assert.Empty(a.Matches);
|
||||
Assert.Null(a.Matches);
|
||||
Assert.Null(a.Parameters);
|
||||
|
||||
next = Assert.Single(a.Literals);
|
||||
Assert.Equal("b", next.Key);
|
||||
|
||||
var b = next.Value;
|
||||
Assert.Empty(b.Matches);
|
||||
Assert.Null(b.Matches);
|
||||
Assert.Null(b.Parameters);
|
||||
|
||||
next = Assert.Single(b.Literals);
|
||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var c = next.Value;
|
||||
Assert.Same(endpoint, Assert.Single(c.Matches));
|
||||
Assert.Null(c.Parameters);
|
||||
Assert.Empty(c.Literals);
|
||||
Assert.Null(c.Literals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -85,21 +85,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Empty(root.Literals);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Literals);
|
||||
|
||||
var a = root.Parameters;
|
||||
Assert.Empty(a.Matches);
|
||||
Assert.Empty(a.Literals);
|
||||
Assert.Null(a.Matches);
|
||||
Assert.Null(a.Literals);
|
||||
|
||||
var b = a.Parameters;
|
||||
Assert.Empty(b.Matches);
|
||||
Assert.Empty(b.Literals);
|
||||
Assert.Null(b.Matches);
|
||||
Assert.Null(b.Literals);
|
||||
|
||||
var c = b.Parameters;
|
||||
Assert.Same(endpoint, Assert.Single(c.Matches));
|
||||
Assert.Null(c.Parameters);
|
||||
Assert.Empty(c.Literals);
|
||||
Assert.Null(c.Literals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -115,21 +115,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Empty(root.Literals);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Literals);
|
||||
|
||||
var a = root.Parameters;
|
||||
|
||||
// The catch all can match a path like '/a'
|
||||
Assert.Same(endpoint, Assert.Single(a.Matches));
|
||||
Assert.Empty(a.Literals);
|
||||
Assert.Null(a.Literals);
|
||||
Assert.Null(a.Parameters);
|
||||
|
||||
// Catch-all nodes include an extra transition that loops to process
|
||||
// extra segments.
|
||||
var catchAll = a.CatchAll;
|
||||
Assert.Same(endpoint, Assert.Single(catchAll.Matches));
|
||||
Assert.Empty(catchAll.Literals);
|
||||
Assert.Null(catchAll.Literals);
|
||||
Assert.Same(catchAll, catchAll.Parameters);
|
||||
Assert.Same(catchAll, catchAll.CatchAll);
|
||||
}
|
||||
|
|
@ -148,13 +148,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
// Assert
|
||||
Assert.Same(endpoint, Assert.Single(root.Matches));
|
||||
Assert.Empty(root.Literals);
|
||||
Assert.Null(root.Literals);
|
||||
|
||||
// Catch-all nodes include an extra transition that loops to process
|
||||
// extra segments.
|
||||
var catchAll = root.CatchAll;
|
||||
Assert.Same(endpoint, Assert.Single(catchAll.Matches));
|
||||
Assert.Empty(catchAll.Literals);
|
||||
Assert.Null(catchAll.Literals);
|
||||
Assert.Same(catchAll, catchAll.Parameters);
|
||||
}
|
||||
|
||||
|
|
@ -174,19 +174,19 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
Assert.Equal("a", next.Key);
|
||||
|
||||
var a = next.Value;
|
||||
Assert.Empty(a.Matches);
|
||||
Assert.Null(a.Matches);
|
||||
|
||||
Assert.Equal(2, a.Literals.Count);
|
||||
|
||||
var b1 = a.Literals["b1"];
|
||||
Assert.Empty(b1.Matches);
|
||||
Assert.Null(b1.Matches);
|
||||
Assert.Null(b1.Parameters);
|
||||
|
||||
next = Assert.Single(b1.Literals);
|
||||
|
|
@ -195,10 +195,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var c1 = next.Value;
|
||||
Assert.Same(endpoint1, Assert.Single(c1.Matches));
|
||||
Assert.Null(c1.Parameters);
|
||||
Assert.Empty(c1.Literals);
|
||||
Assert.Null(c1.Literals);
|
||||
|
||||
var b2 = a.Literals["b2"];
|
||||
Assert.Empty(b2.Matches);
|
||||
Assert.Null(b2.Matches);
|
||||
Assert.Null(b2.Parameters);
|
||||
|
||||
next = Assert.Single(b2.Literals);
|
||||
|
|
@ -207,7 +207,59 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var c2 = next.Value;
|
||||
Assert.Same(endpoint2, Assert.Single(c2.Matches));
|
||||
Assert.Null(c2.Parameters);
|
||||
Assert.Empty(c2.Literals);
|
||||
Assert.Null(c2.Literals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildDfaTree_MultipleEndpoint_LiteralDifferentCase()
|
||||
{
|
||||
// Arrange
|
||||
var builder = CreateDfaMatcherBuilder();
|
||||
|
||||
var endpoint1 = CreateEndpoint("a/b1/c");
|
||||
builder.AddEndpoint(endpoint1);
|
||||
|
||||
var endpoint2 = CreateEndpoint("A/b2/c");
|
||||
builder.AddEndpoint(endpoint2);
|
||||
|
||||
// Act
|
||||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
Assert.Equal("a", next.Key);
|
||||
|
||||
var a = next.Value;
|
||||
Assert.Null(a.Matches);
|
||||
|
||||
Assert.Equal(2, a.Literals.Count);
|
||||
|
||||
var b1 = a.Literals["b1"];
|
||||
Assert.Null(b1.Matches);
|
||||
Assert.Null(b1.Parameters);
|
||||
|
||||
next = Assert.Single(b1.Literals);
|
||||
Assert.Equal("c", next.Key);
|
||||
|
||||
var c1 = next.Value;
|
||||
Assert.Same(endpoint1, Assert.Single(c1.Matches));
|
||||
Assert.Null(c1.Parameters);
|
||||
Assert.Null(c1.Literals);
|
||||
|
||||
var b2 = a.Literals["b2"];
|
||||
Assert.Null(b2.Matches);
|
||||
Assert.Null(b2.Parameters);
|
||||
|
||||
next = Assert.Single(b2.Literals);
|
||||
Assert.Equal("c", next.Key);
|
||||
|
||||
var c2 = next.Value;
|
||||
Assert.Same(endpoint2, Assert.Single(c2.Matches));
|
||||
Assert.Null(c2.Parameters);
|
||||
Assert.Null(c2.Literals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -226,20 +278,20 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
Assert.Equal("a", next.Key);
|
||||
|
||||
var a = next.Value;
|
||||
Assert.Empty(a.Matches);
|
||||
Assert.Null(a.Matches);
|
||||
|
||||
next = Assert.Single(a.Literals);
|
||||
Assert.Equal("b", next.Key);
|
||||
|
||||
var b = next.Value;
|
||||
Assert.Empty(b.Matches);
|
||||
Assert.Null(b.Matches);
|
||||
Assert.Null(b.Parameters);
|
||||
|
||||
next = Assert.Single(b.Literals);
|
||||
|
|
@ -251,10 +303,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
e => Assert.Same(endpoint1, e),
|
||||
e => Assert.Same(endpoint2, e));
|
||||
Assert.Null(c1.Parameters);
|
||||
Assert.Empty(c1.Literals);
|
||||
Assert.Null(c1.Literals);
|
||||
|
||||
var b2 = a.Parameters;
|
||||
Assert.Empty(b2.Matches);
|
||||
Assert.Null(b2.Matches);
|
||||
Assert.Null(b2.Parameters);
|
||||
|
||||
next = Assert.Single(b2.Literals);
|
||||
|
|
@ -263,7 +315,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var c2 = next.Value;
|
||||
Assert.Same(endpoint2, Assert.Single(c2.Matches));
|
||||
Assert.Null(c2.Parameters);
|
||||
Assert.Empty(c2.Literals);
|
||||
Assert.Null(c2.Literals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -282,18 +334,18 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
Assert.Equal("a", next.Key);
|
||||
|
||||
var a = next.Value;
|
||||
Assert.Empty(a.Matches);
|
||||
Assert.Empty(a.Literals);
|
||||
Assert.Null(a.Matches);
|
||||
Assert.Null(a.Literals);
|
||||
|
||||
var b = a.Parameters;
|
||||
Assert.Empty(b.Matches);
|
||||
Assert.Null(b.Matches);
|
||||
Assert.Null(b.Parameters);
|
||||
|
||||
next = Assert.Single(b.Literals);
|
||||
|
|
@ -305,7 +357,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
e => Assert.Same(endpoint1, e),
|
||||
e => Assert.Same(endpoint2, e));
|
||||
Assert.Null(c.Parameters);
|
||||
Assert.Empty(c.Literals);
|
||||
Assert.Null(c.Literals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -324,7 +376,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -349,7 +401,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
e => Assert.Same(endpoint1, e),
|
||||
e => Assert.Same(endpoint2, e));
|
||||
Assert.Null(c1.Parameters);
|
||||
Assert.Empty(c1.Literals);
|
||||
Assert.Null(c1.Literals);
|
||||
|
||||
var catchAll = a.CatchAll;
|
||||
Assert.Same(endpoint2, Assert.Single(catchAll.Matches));
|
||||
|
|
@ -373,7 +425,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -381,7 +433,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
var a = next.Value;
|
||||
Assert.Same(endpoint2, Assert.Single(a.Matches));
|
||||
Assert.Empty(a.Literals);
|
||||
Assert.Null(a.Literals);
|
||||
|
||||
var b1 = a.Parameters;
|
||||
Assert.Same(endpoint2, Assert.Single(a.Matches));
|
||||
|
|
@ -396,7 +448,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
e => Assert.Same(endpoint1, e),
|
||||
e => Assert.Same(endpoint2, e));
|
||||
Assert.Null(c1.Parameters);
|
||||
Assert.Empty(c1.Literals);
|
||||
Assert.Null(c1.Literals);
|
||||
|
||||
var catchAll = a.CatchAll;
|
||||
Assert.Same(endpoint2, Assert.Single(catchAll.Matches));
|
||||
|
|
@ -417,7 +469,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -440,7 +492,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var test2_true = test1_0.PolicyEdges[true];
|
||||
Assert.Same(endpoint1, Assert.Single(test2_true.Matches));
|
||||
Assert.Null(test2_true.NodeBuilder);
|
||||
Assert.Empty(test2_true.PolicyEdges);
|
||||
Assert.Null(test2_true.PolicyEdges);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -462,7 +514,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -486,7 +538,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var test2_true = test1_0.PolicyEdges[true];
|
||||
Assert.Same(endpoint1, Assert.Single(test2_true.Matches));
|
||||
Assert.Null(test2_true.NodeBuilder);
|
||||
Assert.Empty(test2_true.PolicyEdges);
|
||||
Assert.Null(test2_true.PolicyEdges);
|
||||
|
||||
var test1_1 = a.PolicyEdges[1];
|
||||
Assert.Empty(test1_1.Matches);
|
||||
|
|
@ -499,12 +551,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
test2_true = test1_1.PolicyEdges[true];
|
||||
Assert.Same(endpoint2, Assert.Single(test2_true.Matches));
|
||||
Assert.Null(test2_true.NodeBuilder);
|
||||
Assert.Empty(test2_true.PolicyEdges);
|
||||
Assert.Null(test2_true.PolicyEdges);
|
||||
|
||||
var test2_false = test1_1.PolicyEdges[false];
|
||||
Assert.Same(endpoint3, Assert.Single(test2_false.Matches));
|
||||
Assert.Null(test2_false.NodeBuilder);
|
||||
Assert.Empty(test2_false.PolicyEdges);
|
||||
Assert.Null(test2_false.PolicyEdges);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -526,7 +578,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -543,12 +595,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var test2_true = a.PolicyEdges[true];
|
||||
Assert.Equal(new[] { endpoint1, endpoint2, }, test2_true.Matches);
|
||||
Assert.Null(test2_true.NodeBuilder);
|
||||
Assert.Empty(test2_true.PolicyEdges);
|
||||
Assert.Null(test2_true.PolicyEdges);
|
||||
|
||||
var test2_false = a.PolicyEdges[false];
|
||||
Assert.Equal(new[] { endpoint3, }, test2_false.Matches);
|
||||
Assert.Null(test2_false.NodeBuilder);
|
||||
Assert.Empty(test2_false.PolicyEdges);
|
||||
Assert.Null(test2_false.PolicyEdges);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -570,7 +622,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -587,12 +639,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var test1_0 = a.PolicyEdges[0];
|
||||
Assert.Equal(new[] { endpoint1, }, test1_0.Matches);
|
||||
Assert.Null(test1_0.NodeBuilder);
|
||||
Assert.Empty(test1_0.PolicyEdges);
|
||||
Assert.Null(test1_0.PolicyEdges);
|
||||
|
||||
var test1_1 = a.PolicyEdges[1];
|
||||
Assert.Equal(new[] { endpoint2, endpoint3, }, test1_1.Matches);
|
||||
Assert.Null(test1_1.NodeBuilder);
|
||||
Assert.Empty(test1_1.PolicyEdges);
|
||||
Assert.Null(test1_1.PolicyEdges);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -614,7 +666,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -632,12 +684,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var test1_0 = a.PolicyEdges[0];
|
||||
Assert.Equal(new[] { endpoint1, }, test1_0.Matches);
|
||||
Assert.Null(test1_0.NodeBuilder);
|
||||
Assert.Empty(test1_0.PolicyEdges);
|
||||
Assert.Null(test1_0.PolicyEdges);
|
||||
|
||||
var test1_1 = a.PolicyEdges[1];
|
||||
Assert.Equal(new[] { endpoint2, endpoint3, }, test1_1.Matches);
|
||||
Assert.Null(test1_1.NodeBuilder);
|
||||
Assert.Empty(test1_1.PolicyEdges);
|
||||
Assert.Null(test1_1.PolicyEdges);
|
||||
|
||||
var nonRouteEndpoint = a.PolicyEdges[int.MaxValue];
|
||||
Assert.Equal("MaxValueEndpoint", Assert.Single(nonRouteEndpoint.Matches).DisplayName);
|
||||
|
|
@ -662,7 +714,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var root = builder.BuildDfaTree();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(root.Matches);
|
||||
Assert.Null(root.Matches);
|
||||
Assert.Null(root.Parameters);
|
||||
|
||||
var next = Assert.Single(root.Literals);
|
||||
|
|
@ -671,7 +723,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var a = next.Value;
|
||||
Assert.Equal(new[] { endpoint1, endpoint2, endpoint3, }, a.Matches);
|
||||
Assert.Null(a.NodeBuilder);
|
||||
Assert.Empty(a.PolicyEdges);
|
||||
Assert.Null(a.PolicyEdges);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue