File: DecisionTreeBuilderTest.cs
Web Access
Project: src\src\Http\Routing\test\UnitTests\Microsoft.AspNetCore.Routing.Tests.csproj (Microsoft.AspNetCore.Routing.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace Microsoft.AspNetCore.Routing.DecisionTree;
 
public class DecisionTreeBuilderTest
{
    [Fact]
    public void BuildTree_Empty()
    {
        // Arrange
        var items = new List<Item>();
 
        // Act
        var tree = DecisionTreeBuilder<Item>.GenerateTree(items, new ItemClassifier());
 
        // Assert
        Assert.Empty(tree.Criteria);
        Assert.Empty(tree.Matches);
    }
 
    [Fact]
    public void BuildTree_TrivialMatch()
    {
        // Arrange
        var items = new List<Item>();
 
        var item = new Item();
        items.Add(item);
 
        // Act
        var tree = DecisionTreeBuilder<Item>.GenerateTree(items, new ItemClassifier());
 
        // Assert
        Assert.Empty(tree.Criteria);
        Assert.Same(item, Assert.Single(tree.Matches));
    }
 
    [Fact]
    public void BuildTree_WithMultipleCriteria()
    {
        // Arrange
        var items = new List<Item>();
 
        var item = new Item();
        item.Criteria.Add("area", new DecisionCriterionValue(value: "Admin"));
        item.Criteria.Add("controller", new DecisionCriterionValue(value: "Users"));
        item.Criteria.Add("action", new DecisionCriterionValue(value: "AddUser"));
        items.Add(item);
 
        // Act
        var tree = DecisionTreeBuilder<Item>.GenerateTree(items, new ItemClassifier());
 
        // Assert
        Assert.Empty(tree.Matches);
 
        var area = Assert.Single(tree.Criteria);
        Assert.Equal("area", area.Key);
 
        var admin = Assert.Single(area.Branches);
        Assert.Equal("Admin", admin.Key);
        Assert.Empty(admin.Value.Matches);
 
        var controller = Assert.Single(admin.Value.Criteria);
        Assert.Equal("controller", controller.Key);
 
        var users = Assert.Single(controller.Branches);
        Assert.Equal("Users", users.Key);
        Assert.Empty(users.Value.Matches);
 
        var action = Assert.Single(users.Value.Criteria);
        Assert.Equal("action", action.Key);
 
        var addUser = Assert.Single(action.Branches);
        Assert.Equal("AddUser", addUser.Key);
        Assert.Empty(addUser.Value.Criteria);
        Assert.Same(item, Assert.Single(addUser.Value.Matches));
    }
 
    [Fact]
    public void BuildTree_WithMultipleItems()
    {
        // Arrange
        var items = new List<Item>();
 
        var item1 = new Item();
        item1.Criteria.Add("controller", new DecisionCriterionValue(value: "Store"));
        item1.Criteria.Add("action", new DecisionCriterionValue(value: "Buy"));
        items.Add(item1);
 
        var item2 = new Item();
        item2.Criteria.Add("controller", new DecisionCriterionValue(value: "Store"));
        item2.Criteria.Add("action", new DecisionCriterionValue(value: "Checkout"));
        items.Add(item2);
 
        // Act
        var tree = DecisionTreeBuilder<Item>.GenerateTree(items, new ItemClassifier());
 
        // Assert
        Assert.Empty(tree.Matches);
 
        var action = Assert.Single(tree.Criteria);
        Assert.Equal("action", action.Key);
 
        var buy = action.Branches["Buy"];
        Assert.Empty(buy.Matches);
 
        var controller = Assert.Single(buy.Criteria);
        Assert.Equal("controller", controller.Key);
 
        var store = Assert.Single(controller.Branches);
        Assert.Equal("Store", store.Key);
        Assert.Empty(store.Value.Criteria);
        Assert.Same(item1, Assert.Single(store.Value.Matches));
 
        var checkout = action.Branches["Checkout"];
        Assert.Empty(checkout.Matches);
 
        controller = Assert.Single(checkout.Criteria);
        Assert.Equal("controller", controller.Key);
 
        store = Assert.Single(controller.Branches);
        Assert.Equal("Store", store.Key);
        Assert.Empty(store.Value.Criteria);
        Assert.Same(item2, Assert.Single(store.Value.Matches));
    }
 
    [Fact]
    public void BuildTree_WithInteriorMatch()
    {
        // Arrange
        var items = new List<Item>();
 
        var item1 = new Item();
        item1.Criteria.Add("controller", new DecisionCriterionValue(value: "Store"));
        item1.Criteria.Add("action", new DecisionCriterionValue(value: "Buy"));
        items.Add(item1);
 
        var item2 = new Item();
        item2.Criteria.Add("controller", new DecisionCriterionValue(value: "Store"));
        item2.Criteria.Add("action", new DecisionCriterionValue(value: "Checkout"));
        items.Add(item2);
 
        var item3 = new Item();
        item3.Criteria.Add("action", new DecisionCriterionValue(value: "Buy"));
        items.Add(item3);
 
        // Act
        var tree = DecisionTreeBuilder<Item>.GenerateTree(items, new ItemClassifier());
 
        // Assert
        Assert.Empty(tree.Matches);
 
        var action = Assert.Single(tree.Criteria);
        Assert.Equal("action", action.Key);
 
        var buy = action.Branches["Buy"];
        Assert.Same(item3, Assert.Single(buy.Matches));
    }
 
    [Fact]
    public void BuildTree_WithDivergentCriteria()
    {
        // Arrange
        var items = new List<Item>();
 
        var item1 = new Item();
        item1.Criteria.Add("controller", new DecisionCriterionValue(value: "Store"));
        item1.Criteria.Add("action", new DecisionCriterionValue(value: "Buy"));
        items.Add(item1);
 
        var item2 = new Item();
        item2.Criteria.Add("controller", new DecisionCriterionValue(value: "Store"));
        item2.Criteria.Add("action", new DecisionCriterionValue(value: "Checkout"));
        items.Add(item2);
 
        var item3 = new Item();
        item3.Criteria.Add("stub", new DecisionCriterionValue(value: "Bleh"));
        items.Add(item3);
 
        // Act
        var tree = DecisionTreeBuilder<Item>.GenerateTree(items, new ItemClassifier());
 
        // Assert
        Assert.Empty(tree.Matches);
 
        var action = tree.Criteria[0];
        Assert.Equal("action", action.Key);
 
        var stub = tree.Criteria[1];
        Assert.Equal("stub", stub.Key);
    }
 
    private class Item
    {
        public Item()
        {
            Criteria = new Dictionary<string, DecisionCriterionValue>(StringComparer.OrdinalIgnoreCase);
        }
 
        public Dictionary<string, DecisionCriterionValue> Criteria { get; private set; }
    }
 
    private class ItemClassifier : IClassifier<Item>
    {
        public IEqualityComparer<object> ValueComparer => RouteValueEqualityComparer.Default;
 
        public IDictionary<string, DecisionCriterionValue> GetCriteria(Item item)
        {
            return item.Criteria;
        }
    }
}