Show a flattened tree in LinkGenerationDecisionTree's DebuggerDisplayString
[Fixes #636] Flatten the LinkGenerationDecisionTree to show as debugger display string
This commit is contained in:
parent
34499dbe24
commit
71cb933a08
|
|
@ -3,12 +3,16 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Routing.DecisionTree;
|
||||
using Microsoft.AspNetCore.Routing.Tree;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Internal
|
||||
{
|
||||
// A decision tree that matches link generation entries based on route data.
|
||||
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
|
||||
public class LinkGenerationDecisionTree
|
||||
{
|
||||
private readonly DecisionTreeNode<OutboundMatch> _root;
|
||||
|
|
@ -160,5 +164,51 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
y.Match.Entry.RouteTemplate.TemplateText);
|
||||
}
|
||||
}
|
||||
|
||||
// Example output:
|
||||
//
|
||||
// => action: Buy => controller: Store => version: V1(Matches: Store/Buy/V1)
|
||||
// => action: Buy => controller: Store => version: V2(Matches: Store/Buy/V2)
|
||||
// => action: Buy => controller: Store => area: Admin(Matches: Admin/Store/Buy)
|
||||
// => action: Buy => controller: Products(Matches: Products/Buy)
|
||||
// => action: Cart => controller: Store(Matches: Store/Cart)
|
||||
internal string DebuggerDisplayString
|
||||
{
|
||||
get
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var branchStack = new Stack<string>();
|
||||
branchStack.Push(string.Empty);
|
||||
FlattenTree(_root, branchStack, sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void FlattenTree(DecisionTreeNode<OutboundMatch> node, Stack<string> branchStack, StringBuilder sb)
|
||||
{
|
||||
// leaf node
|
||||
if (node.Criteria.Count == 0)
|
||||
{
|
||||
var temp = new StringBuilder();
|
||||
foreach (var branch in branchStack)
|
||||
{
|
||||
temp.Insert(0, branch);
|
||||
}
|
||||
sb.Append(temp.ToString());
|
||||
sb.Append(" (Matches: ");
|
||||
sb.Append(string.Join(", ", node.Matches.Select(m => m.Entry.RouteTemplate.TemplateText)));
|
||||
sb.AppendLine(")");
|
||||
}
|
||||
|
||||
foreach (var criterion in node.Criteria)
|
||||
{
|
||||
foreach (var branch in criterion.Branches)
|
||||
{
|
||||
branchStack.Push($" => {criterion.Key}: {branch.Key}");
|
||||
FlattenTree(branch.Value, branchStack, sb);
|
||||
branchStack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
// 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.Http;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
using Microsoft.AspNetCore.Routing.Tree;
|
||||
using Xunit;
|
||||
|
|
@ -318,11 +320,45 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
Assert.Equal(entries, matches);
|
||||
}
|
||||
|
||||
private OutboundMatch CreateMatch(object requiredValues)
|
||||
[Fact]
|
||||
public void ToDebuggerDisplayString_GivesAFlattenedTree()
|
||||
{
|
||||
// Arrange
|
||||
var entries = new List<OutboundMatch>();
|
||||
entries.Add(CreateMatch(new { action = "Buy", controller = "Store", version = "V1" }, "Store/Buy/V1"));
|
||||
entries.Add(CreateMatch(new { action = "Buy", controller = "Store", area = "Admin" }, "Admin/Store/Buy"));
|
||||
entries.Add(CreateMatch(new { action = "Buy", controller = "Products" }, "Products/Buy"));
|
||||
entries.Add(CreateMatch(new { action = "Buy", controller = "Store", version = "V2" }, "Store/Buy/V2"));
|
||||
entries.Add(CreateMatch(new { action = "Cart", controller = "Store" }, "Store/Cart"));
|
||||
entries.Add(CreateMatch(new { action = "Index", controller = "Home" }, "Home/Index/{id?}"));
|
||||
var tree = new LinkGenerationDecisionTree(entries);
|
||||
var newLine = Environment.NewLine;
|
||||
var expected =
|
||||
" => action: Buy => controller: Store => version: V1 (Matches: Store/Buy/V1)" + newLine +
|
||||
" => action: Buy => controller: Store => version: V2 (Matches: Store/Buy/V2)" + newLine +
|
||||
" => action: Buy => controller: Store => area: Admin (Matches: Admin/Store/Buy)" + newLine +
|
||||
" => action: Buy => controller: Products (Matches: Products/Buy)" + newLine +
|
||||
" => action: Cart => controller: Store (Matches: Store/Cart)" + newLine +
|
||||
" => action: Index => controller: Home (Matches: Home/Index/{id?})" + newLine;
|
||||
|
||||
// Act
|
||||
var flattenedTree = tree.DebuggerDisplayString;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, flattenedTree);
|
||||
}
|
||||
|
||||
private OutboundMatch CreateMatch(object requiredValues, string routeTemplate = null)
|
||||
{
|
||||
var match = new OutboundMatch();
|
||||
match.Entry = new OutboundRouteEntry();
|
||||
match.Entry.RequiredLinkValues = new RouteValueDictionary(requiredValues);
|
||||
|
||||
if (!string.IsNullOrEmpty(routeTemplate))
|
||||
{
|
||||
match.Entry.RouteTemplate = new RouteTemplate(RoutePatternFactory.Parse(routeTemplate));
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue